2019-05-09 09:32:32 -08:00
|
|
|
const {moveSync, copySync, existsSync, writeFileSync, readFileSync, lstatSync} = require('fs-extra');
|
2017-08-21 16:07:50 -08:00
|
|
|
const {sync: mkdirpSync} = require('mkdirp');
|
2019-05-08 10:56:45 -08:00
|
|
|
const {defaultCfg, cfgPath, legacyCfgPath, plugs, defaultPlatformKeyPath} = require('./paths');
|
2017-09-20 13:32:32 -08:00
|
|
|
const {_init, _extractDefault} = require('./init');
|
2019-05-08 10:56:45 -08:00
|
|
|
const notify = require('../notify');
|
2017-06-02 16:03:47 -08:00
|
|
|
|
2017-09-20 13:32:32 -08:00
|
|
|
let defaultConfig;
|
|
|
|
|
|
2017-09-10 05:35:10 -08:00
|
|
|
const _write = function(path, data) {
|
2017-06-02 16:03:47 -08:00
|
|
|
// This method will take text formatted as Unix line endings and transform it
|
|
|
|
|
// to text formatted with DOS line endings. We do this because the default
|
|
|
|
|
// text editor on Windows (notepad) doesn't Deal with LF files. Still. In 2017.
|
2017-09-10 05:35:10 -08:00
|
|
|
const crlfify = function(str) {
|
2017-06-02 16:03:47 -08:00
|
|
|
return str.replace(/\r?\n/g, '\r\n');
|
|
|
|
|
};
|
|
|
|
|
const format = process.platform === 'win32' ? crlfify(data.toString()) : data;
|
|
|
|
|
writeFileSync(path, format, 'utf8');
|
|
|
|
|
};
|
|
|
|
|
|
2019-05-08 10:56:45 -08:00
|
|
|
// Saves a file as backup by appending '.backup' or '.backup2', '.backup3', etc.
|
|
|
|
|
// so as to not override any existing files
|
|
|
|
|
const saveAsBackup = src => {
|
|
|
|
|
let attempt = 1;
|
|
|
|
|
while (attempt < 100) {
|
|
|
|
|
try {
|
|
|
|
|
const backupPath = src + '.backup' + (attempt === 1 ? '' : attempt);
|
|
|
|
|
moveSync(src, backupPath);
|
|
|
|
|
return backupPath;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
if (e.code === 'EEXIST') {
|
|
|
|
|
attempt++;
|
|
|
|
|
} else {
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
throw new Error('Failed to create backup for config file. Too many backups');
|
|
|
|
|
};
|
|
|
|
|
|
2019-05-09 09:32:32 -08:00
|
|
|
// Migrate Hyper2 config to Hyper3 but only if the user hasn't manually
|
|
|
|
|
// touched the new config and if the old config is not a symlink
|
|
|
|
|
const migrateHyper2Config = () => {
|
|
|
|
|
if (cfgPath === legacyCfgPath) {
|
|
|
|
|
// No need to migrate
|
2019-05-08 10:56:45 -08:00
|
|
|
return;
|
|
|
|
|
}
|
2019-05-09 09:32:32 -08:00
|
|
|
if (!existsSync(legacyCfgPath)) {
|
|
|
|
|
// Already migrated or user never used Hyper 2
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const existsNew = existsSync(cfgPath);
|
|
|
|
|
if (lstatSync(legacyCfgPath).isSymbolicLink() || (existsNew && lstatSync(cfgPath).isSymbolicLink())) {
|
|
|
|
|
// One of the files is a symlink, there could be a number of complications
|
|
|
|
|
// in this case so let's avoid those and not do automatic migration
|
|
|
|
|
return;
|
2019-05-08 10:56:45 -08:00
|
|
|
}
|
|
|
|
|
|
2019-05-09 10:31:11 -08:00
|
|
|
if (existsNew) {
|
|
|
|
|
const cfg1 = readFileSync(defaultCfg, 'utf8').replace(/\r|\n/g, '');
|
|
|
|
|
const cfg2 = readFileSync(cfgPath, 'utf8').replace(/\r|\n/g, '');
|
|
|
|
|
const hasNewConfigBeenTouched = cfg1 !== cfg2;
|
|
|
|
|
if (hasNewConfigBeenTouched) {
|
|
|
|
|
// Assume the user has migrated manually but rename old config to .backup so
|
|
|
|
|
// we don't keep trying to migrate on every launch
|
|
|
|
|
const backupPath = saveAsBackup(legacyCfgPath);
|
|
|
|
|
notify(
|
|
|
|
|
'Hyper 3',
|
|
|
|
|
`Settings location has changed to ${cfgPath}.\nWe've backed up your old Hyper config to ${backupPath}`
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-05-08 10:56:45 -08:00
|
|
|
}
|
|
|
|
|
|
2019-05-09 09:32:32 -08:00
|
|
|
// Migrate
|
|
|
|
|
copySync(legacyCfgPath, cfgPath);
|
|
|
|
|
saveAsBackup(legacyCfgPath);
|
|
|
|
|
|
|
|
|
|
notify(
|
|
|
|
|
'Hyper 3',
|
|
|
|
|
`Settings location has changed to ${cfgPath}.\nWe've automatically migrated your existing config!\nPlease restart Hyper now`
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const _importConf = function() {
|
|
|
|
|
// init plugin directories if not present
|
|
|
|
|
mkdirpSync(plugs.base);
|
2017-08-21 16:07:50 -08:00
|
|
|
mkdirpSync(plugs.local);
|
|
|
|
|
|
2019-05-09 09:32:32 -08:00
|
|
|
try {
|
|
|
|
|
migrateHyper2Config();
|
|
|
|
|
} catch (err) {
|
|
|
|
|
//eslint-disable-next-line no-console
|
|
|
|
|
console.error(err);
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-02 16:03:47 -08:00
|
|
|
try {
|
2017-11-03 15:42:25 -08:00
|
|
|
const defaultCfgRaw = readFileSync(defaultCfg, 'utf8');
|
|
|
|
|
const _defaultCfg = _extractDefault(defaultCfgRaw);
|
2017-11-02 18:51:18 -08:00
|
|
|
// Importing platform specific keymap
|
|
|
|
|
try {
|
|
|
|
|
const content = readFileSync(defaultPlatformKeyPath(), 'utf8');
|
|
|
|
|
const mapping = JSON.parse(content);
|
|
|
|
|
_defaultCfg.keymaps = mapping;
|
|
|
|
|
} catch (err) {
|
|
|
|
|
//eslint-disable-next-line no-console
|
|
|
|
|
console.error(err);
|
|
|
|
|
}
|
2019-05-08 10:56:45 -08:00
|
|
|
|
|
|
|
|
// Import user config
|
2017-06-02 16:03:47 -08:00
|
|
|
try {
|
2019-05-08 10:56:45 -08:00
|
|
|
const userCfg = readFileSync(cfgPath, 'utf8');
|
|
|
|
|
return {userCfg, defaultCfg: _defaultCfg};
|
2017-06-02 16:03:47 -08:00
|
|
|
} catch (err) {
|
2017-11-03 15:42:25 -08:00
|
|
|
_write(cfgPath, defaultCfgRaw);
|
|
|
|
|
return {userCfg: defaultCfgRaw, defaultCfg: _defaultCfg};
|
2017-06-02 16:03:47 -08:00
|
|
|
}
|
|
|
|
|
} catch (err) {
|
2017-09-10 05:35:10 -08:00
|
|
|
//eslint-disable-next-line no-console
|
2017-06-02 16:03:47 -08:00
|
|
|
console.log(err);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2017-09-20 13:32:32 -08:00
|
|
|
exports._import = () => {
|
|
|
|
|
const imported = _importConf();
|
2017-11-02 18:51:18 -08:00
|
|
|
defaultConfig = imported.defaultCfg;
|
2017-11-03 15:42:25 -08:00
|
|
|
const result = _init(imported);
|
|
|
|
|
return result;
|
2017-06-02 16:03:47 -08:00
|
|
|
};
|
|
|
|
|
|
2017-09-20 13:32:32 -08:00
|
|
|
exports.getDefaultConfig = () => {
|
|
|
|
|
if (!defaultConfig) {
|
|
|
|
|
defaultConfig = _extractDefault(_importConf().defaultCfg);
|
|
|
|
|
}
|
|
|
|
|
return defaultConfig;
|
|
|
|
|
};
|