From a5f86d55c62f6c7f674d9aec1cca6bf1adda6d20 Mon Sep 17 00:00:00 2001 From: Juan Campa Date: Wed, 8 May 2019 14:56:45 -0400 Subject: [PATCH 1/4] Add migration path from Hyper2 config location to Hyper3 (#3610) * Add migration path from Hyper2 config location to Hyper3 * Use fs-extra, not fs-extra-p * Better approach that also handles plugin migration * Remove plugins migrationn * Migrate local plugins * Empty to force CI --- app/config/import.js | 62 ++++++++++++++++++++++++++++++++++++++++---- app/config/paths.js | 6 ++++- app/package.json | 1 + app/yarn.lock | 26 +++++++++++++++++++ 4 files changed, 89 insertions(+), 6 deletions(-) diff --git a/app/config/import.js b/app/config/import.js index 58394457..bfd2e81e 100644 --- a/app/config/import.js +++ b/app/config/import.js @@ -1,7 +1,8 @@ -const {writeFileSync, readFileSync} = require('fs'); +const {moveSync, copySync, existsSync, writeFileSync, readFileSync} = require('fs-extra'); const {sync: mkdirpSync} = require('mkdirp'); -const {defaultCfg, cfgPath, plugs, defaultPlatformKeyPath} = require('./paths'); +const {defaultCfg, cfgPath, legacyCfgPath, plugs, defaultPlatformKeyPath} = require('./paths'); const {_init, _extractDefault} = require('./init'); +const notify = require('../notify'); let defaultConfig; @@ -16,9 +17,59 @@ const _write = function(path, data) { writeFileSync(path, format, 'utf8'); }; +// 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'); +}; + +const migrate = (old, _new, oldBackupPath) => { + if (old === _new) { + return; + } + if (existsSync(old)) { + //eslint-disable-next-line no-console + console.log('Found legacy config. Migrating ', old, '->', _new); + if (existsSync(_new)) { + saveAsBackup(_new); + } + copySync(old, _new); + saveAsBackup(oldBackupPath || old); + return true; + } + return false; +}; + const _importConf = function() { // init plugin directories if not present mkdirpSync(plugs.base); + + // Migrate Hyper2 config to Hyper3 + const migratedConfig = migrate(legacyCfgPath, cfgPath); + const migratedPlugins = migrate(plugs.legacyLocal, plugs.local, plugs.legacyBase); + if (migratedConfig || migratedPlugins) { + notify( + 'Hyper 3', + `Settings location has changed to ${cfgPath}.\nWe've automatically migrated your existing config!\nPlease restart hyper` + ); + } + + // Run this after the migration so that we don't generate a ".backup" file for + // an empty local/ directory mkdirpSync(plugs.local); try { @@ -33,10 +84,11 @@ const _importConf = function() { //eslint-disable-next-line no-console console.error(err); } - // Importing user config + + // Import user config try { - const _cfgPath = readFileSync(cfgPath, 'utf8'); - return {userCfg: _cfgPath, defaultCfg: _defaultCfg}; + const userCfg = readFileSync(cfgPath, 'utf8'); + return {userCfg, defaultCfg: _defaultCfg}; } catch (err) { _write(cfgPath, defaultCfgRaw); return {userCfg: defaultCfgRaw, defaultCfg: _defaultCfg}; diff --git a/app/config/paths.js b/app/config/paths.js index a9cadf01..d662a150 100644 --- a/app/config/paths.js +++ b/app/config/paths.js @@ -16,8 +16,9 @@ const applicationDirectory = ? join(process.env.XDG_CONFIG_HOME, 'hyper') : process.platform == 'win32' ? app.getPath('userData') : homedir(); -let cfgPath = join(applicationDirectory, cfgFile); let cfgDir = applicationDirectory; +let cfgPath = join(applicationDirectory, cfgFile); +let legacyCfgPath = join(homeDirectory, cfgFile); // Hyper 2 config location const devDir = resolve(__dirname, '../..'); const devCfg = join(devDir, cfgFile); @@ -38,6 +39,8 @@ if (isDev) { const plugins = resolve(cfgDir, '.hyper_plugins'); const plugs = { + legacyBase: resolve(homeDirectory, '.hyper_plugins'), + legacyLocal: resolve(homeDirectory, '.hyper_plugins', 'local'), base: plugins, local: resolve(plugins, 'local'), cache: resolve(plugins, 'cache') @@ -69,6 +72,7 @@ const defaultPlatformKeyPath = () => { module.exports = { cfgDir, cfgPath, + legacyCfgPath, cfgFile, defaultCfg, icon, diff --git a/app/package.json b/app/package.json index 8b5db9cf..d2b25c73 100644 --- a/app/package.json +++ b/app/package.json @@ -19,6 +19,7 @@ "electron-is-dev": "1.0.1", "electron-squirrel-startup": "1.0.0", "file-uri-to-path": "1.0.0", + "fs-extra": "7.0.1", "git-describe": "4.0.2", "lodash": "4.17.5", "mkdirp": "0.5.1", diff --git a/app/yarn.lock b/app/yarn.lock index 76a8cd9c..a1f848a7 100644 --- a/app/yarn.lock +++ b/app/yarn.lock @@ -192,6 +192,15 @@ find-up@^2.1.0: dependencies: locate-path "^2.0.0" +fs-extra@7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + get-stream@^2.2.0: version "2.3.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" @@ -218,6 +227,11 @@ graceful-fs@^4.1.11: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" +graceful-fs@^4.1.2, graceful-fs@^4.1.6: + version "4.1.15" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" + integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== + iconv-lite@~0.4.13: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" @@ -278,6 +292,13 @@ js-tokens@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + lcid@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" @@ -623,6 +644,11 @@ ua-parser-js@^0.7.9: version "0.7.18" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.18.tgz#a7bfd92f56edfb117083b69e31d2aa8882d4b1ed" +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + uuid@3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" From 1c87f255b3eb1e06ece3049555f0241f7e1e4caa Mon Sep 17 00:00:00 2001 From: Juan Campa Date: Wed, 8 May 2019 15:13:38 -0400 Subject: [PATCH 2/4] 3.0.1-canary.1 --- app/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/package.json b/app/package.json index d2b25c73..7809df81 100644 --- a/app/package.json +++ b/app/package.json @@ -2,7 +2,7 @@ "name": "hyper", "productName": "Hyper", "description": "A terminal built on web technologies", - "version": "3.0.0-canary.10", + "version": "3.0.1-canary.1", "license": "MIT", "author": { "name": "ZEIT, Inc.", From b16de26cf930fc842287b2a745e32975f85a1d55 Mon Sep 17 00:00:00 2001 From: CHaBou Date: Wed, 8 May 2019 23:18:21 +0200 Subject: [PATCH 3/4] fix(cli): fix config path (#3636) --- cli/api.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cli/api.js b/cli/api.js index 590a571a..ad76ba96 100644 --- a/cli/api.js +++ b/cli/api.js @@ -6,13 +6,19 @@ const pify = require('pify'); const recast = require('recast'); const path = require('path'); +// If the user defines XDG_CONFIG_HOME they definitely want their config there, +// otherwise use the home directory in linux/mac and userdata in windows +const applicationDirectory = + process.env.XDG_CONFIG_HOME !== undefined + ? path.join(process.env.XDG_CONFIG_HOME, 'hyper') + : process.platform == 'win32' ? path.join(process.env.APPDATA, 'Hyper') : os.homedir(); + const devConfigFileName = path.join(__dirname, `../.hyper.js`); let fileName = process.env.NODE_ENV !== 'production' && fs.existsSync(devConfigFileName) ? devConfigFileName - : `${os.homedir()}/.hyper.js`; - + : path.join(applicationDirectory, '.hyper.js'); /** * We need to make sure the file reading and parsing is lazy so that failure to * statically analyze the hyper configuration isn't fatal for all kinds of From f73a23055b475bc05c46bc7d2cdd2d1156f8861e Mon Sep 17 00:00:00 2001 From: Juan Campa Date: Wed, 8 May 2019 17:23:49 -0400 Subject: [PATCH 4/4] 3.0.1-canary.2 --- app/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/package.json b/app/package.json index 7809df81..0e98e1bc 100644 --- a/app/package.json +++ b/app/package.json @@ -2,7 +2,7 @@ "name": "hyper", "productName": "Hyper", "description": "A terminal built on web technologies", - "version": "3.0.1-canary.1", + "version": "3.0.1-canary.2", "license": "MIT", "author": { "name": "ZEIT, Inc.",