Merge pull request #185 from VishwasShashidhar/electron-126

Electron 126
This commit is contained in:
Vikas Shashidhar 2017-09-13 14:41:18 +05:30 committed by GitHub
commit fa2c96cfbd
5 changed files with 98 additions and 155 deletions

View File

@ -4,15 +4,16 @@ const electron = require('electron');
const app = electron.app; const app = electron.app;
const path = require('path'); const path = require('path');
const fs = require('fs'); const fs = require('fs');
const AppDirectory = require('appdirectory');
const omit = require('lodash.omit');
const isDevEnv = require('./utils/misc.js').isDevEnv; const isDevEnv = require('./utils/misc.js').isDevEnv;
const isMac = require('./utils/misc.js').isMac; const isMac = require('./utils/misc.js').isMac;
const getRegistry = require('./utils/getRegistry.js'); const getRegistry = require('./utils/getRegistry.js');
const configFileName = 'Symphony.config'; const log = require('./log.js');
const logLevels = require('./enums/logLevels.js');
// For modifying user config while installation const configFileName = 'Symphony.config';
const pick = require('lodash.pick');
const childProcess = require('child_process');
const AppDirectory = require('appdirectory');
const dirs = new AppDirectory('Symphony'); const dirs = new AppDirectory('Symphony');
// cached config when first reading files. initially undefined and will be // cached config when first reading files. initially undefined and will be
@ -20,6 +21,8 @@ const dirs = new AppDirectory('Symphony');
let userConfig; let userConfig;
let globalConfig; let globalConfig;
let ignoreSettings = ['minimizeOnClose', 'launchOnStartup', 'alwaysOnTop', 'url'];
/** /**
* Tries to read given field from user config file, if field doesn't exist * Tries to read given field from user config file, if field doesn't exist
* then tries reading from global config. User config is stord in directory: * then tries reading from global config. User config is stord in directory:
@ -35,10 +38,10 @@ let globalConfig;
*/ */
function getConfigField(fieldName) { function getConfigField(fieldName) {
return getUserConfigField(fieldName) return getUserConfigField(fieldName)
.then(function(value) { .then((value) => {
// got value from user config // got value from user config
return value; return value;
}, function() { }, () => {
// failed to get value from user config, so try global config // failed to get value from user config, so try global config
return getGlobalConfigField(fieldName); return getGlobalConfigField(fieldName);
}); });
@ -50,7 +53,7 @@ function getConfigField(fieldName) {
* @returns {Promise} * @returns {Promise}
*/ */
function getUserConfigField(fieldName) { function getUserConfigField(fieldName) {
return readUserConfig().then(function(config) { return readUserConfig().then((config) => {
if (typeof fieldName === 'string' && fieldName in config) { if (typeof fieldName === 'string' && fieldName in config) {
return config[fieldName]; return config[fieldName];
} }
@ -65,7 +68,7 @@ function getUserConfigField(fieldName) {
* @returns {Promise} * @returns {Promise}
*/ */
function readUserConfig(customConfigPath) { function readUserConfig(customConfigPath) {
return new Promise(function(resolve, reject) { return new Promise((resolve, reject) => {
if (userConfig) { if (userConfig) {
resolve(userConfig); resolve(userConfig);
return; return;
@ -77,7 +80,7 @@ function readUserConfig(customConfigPath) {
configPath = path.join(app.getPath('userData'), configFileName); configPath = path.join(app.getPath('userData'), configFileName);
} }
fs.readFile(configPath, 'utf8', function(err, data) { fs.readFile(configPath, 'utf8', (err, data) => {
if (err) { if (err) {
reject('cannot open user config file: ' + configPath + ', error: ' + err); reject('cannot open user config file: ' + configPath + ', error: ' + err);
} else { } else {
@ -100,7 +103,7 @@ function readUserConfig(customConfigPath) {
* @returns {Promise} * @returns {Promise}
*/ */
function getGlobalConfigField(fieldName) { function getGlobalConfigField(fieldName) {
return readGlobalConfig().then(function(config) { return readGlobalConfig().then((config) => {
if (typeof fieldName === 'string' && fieldName in config) { if (typeof fieldName === 'string' && fieldName in config) {
return config[fieldName]; return config[fieldName];
} }
@ -118,7 +121,7 @@ function getGlobalConfigField(fieldName) {
* installed app). for dev env, the file is read directly from packed asar file. * installed app). for dev env, the file is read directly from packed asar file.
*/ */
function readGlobalConfig() { function readGlobalConfig() {
return new Promise(function(resolve, reject) { return new Promise((resolve, reject) => {
if (globalConfig) { if (globalConfig) {
resolve(globalConfig); resolve(globalConfig);
return; return;
@ -138,7 +141,7 @@ function readGlobalConfig() {
configPath = path.join(execPath, isMac ? '..' : '', globalConfigFileName); configPath = path.join(execPath, isMac ? '..' : '', globalConfigFileName);
} }
fs.readFile(configPath, 'utf8', function(err, data) { fs.readFile(configPath, 'utf8', (err, data) => {
if (err) { if (err) {
reject('cannot open global config file: ' + configPath + ', error: ' + err); reject('cannot open global config file: ' + configPath + ', error: ' + err);
} else { } else {
@ -149,10 +152,10 @@ function readGlobalConfig() {
reject('can not parse config file data: ' + data + ', error: ' + err); reject('can not parse config file data: ' + data + ', error: ' + err);
} }
getRegistry('PodUrl') getRegistry('PodUrl')
.then(function(url) { .then((url) => {
globalConfig.url = url; globalConfig.url = url;
resolve(globalConfig); resolve(globalConfig);
}).catch(function() { }).catch(() => {
resolve(globalConfig); resolve(globalConfig);
}); });
} }
@ -168,9 +171,9 @@ function readGlobalConfig() {
*/ */
function updateConfigField(fieldName, newValue) { function updateConfigField(fieldName, newValue) {
return readUserConfig() return readUserConfig()
.then(function(config) { .then((config) => {
return saveUserConfig(fieldName, newValue, config); return saveUserConfig(fieldName, newValue, config);
}, function() { }, () => {
// in case config doesn't exist, can't read or is corrupted. // in case config doesn't exist, can't read or is corrupted.
// add configVersion - just in case in future we need to provide // add configVersion - just in case in future we need to provide
// upgrade capabilities. // upgrade capabilities.
@ -188,7 +191,7 @@ function updateConfigField(fieldName, newValue) {
* @returns {Promise} * @returns {Promise}
*/ */
function saveUserConfig(fieldName, newValue, oldConfig) { function saveUserConfig(fieldName, newValue, oldConfig) {
return new Promise(function(resolve, reject) { return new Promise((resolve, reject) => {
let configPath = path.join(app.getPath('userData'), configFileName); let configPath = path.join(app.getPath('userData'), configFileName);
if (!oldConfig || !fieldName) { if (!oldConfig || !fieldName) {
@ -214,129 +217,100 @@ function saveUserConfig(fieldName, newValue, oldConfig) {
} }
/** /**
* Method to update multiple user config field * Updates the existing user config settings by removing
* @param {Object} newGlobalConfig - The latest config changes from installer * 'minimizeOnClose', 'launchOnStartup', 'url' and 'alwaysOnTop'
* @param {Object} oldUserConfig - The old user config data * @param {Object} oldUserConfig the old user config object
* @returns {Promise}
*/ */
function updateUserConfig(newGlobalConfig, oldUserConfig) { function updateUserConfig(oldUserConfig) {
return new Promise((resolve, reject) => {
// Picking some values from global config to overwrite user config
const configDataToUpdate = pick(newGlobalConfig, ['url', 'minimizeOnClose', 'launchOnStartup', 'alwaysOnTop']);
const updatedUserConfigData = Object.assign(oldUserConfig, configDataToUpdate);
const jsonNewConfig = JSON.stringify(updatedUserConfigData, null, ' ');
// get user config path
let userConfigFile;
return new Promise((resolve, reject) => {
// create a new object from the old user config
// by ommitting the user related settings from
// the old user config
let newUserConfig = omit(oldUserConfig, ignoreSettings);
let newUserConfigString = JSON.stringify(newUserConfig, null, 2);
// get the user config path
let userConfigFile;
if (isMac) { if (isMac) {
userConfigFile = path.join(dirs.userConfig(), configFileName); userConfigFile = path.join(dirs.userConfig(), configFileName);
} else { } else {
userConfigFile = path.join(app.getPath('userData'), configFileName); userConfigFile = path.join(app.getPath('userData'), configFileName);
} }
fs.writeFile(userConfigFile, jsonNewConfig, 'utf8', (err) => { if (!userConfigFile) {
if (err) { return reject('user config file doesn\'t exist');
reject(err); }
return;
} // write the new user config changes to the user config file
resolve(); fs.writeFileSync(userConfigFile, newUserConfigString, 'utf-8');
});
return resolve();
}); });
} }
/** /**
* Method to overwrite user config on windows installer * Manipulates user config on windows
* @param {String} perUserInstall - Is a flag to determine whether we are installing for per user * @param {String} perUserInstall - Is a flag to determine if we are installing for an individual user
* @returns {Promise} * @returns {Promise}
*/ */
function updateUserConfigWin(perUserInstall) { function updateUserConfigWin(perUserInstall) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// we get the user config path using electron
const userConfigFile = path.join(app.getPath('userData'), configFileName); const userConfigFile = path.join(app.getPath('userData'), configFileName);
// flag to determine whether per user installation
if (!perUserInstall) { // if it's not a per user installation or if the
// user config file doesn't exist, we simple move on
if (!perUserInstall || !fs.existsSync(userConfigFile)) {
log.send(logLevels.WARN, 'config: Could not find the user config file!');
reject(); reject();
return; return;
} }
// if user config file does't exists just copy global config file // In case the file exists, we remove it so that all the
if (!fs.existsSync(userConfigFile)) { // values are fetched from the global config
resolve(copyConfigWin()); // https://perzoinc.atlassian.net/browse/ELECTRON-126
return; readUserConfig(userConfigFile).then((data) => {
} resolve(updateUserConfig(data));
}).catch((err) => {
reject(err);
});
Promise.all([readGlobalConfig(), readUserConfig(userConfigFile)])
.then((data) => {
resolve(updateUserConfig(data[0], data[1]));
})
.catch((err) => {
reject(err);
});
}); });
} }
/** /**
* Method to overwrite user config on mac installer * Manipulates user config on macOS
* @param {String} globalConfigPath - The global config path from installer * @param {String} globalConfigPath - The global config path from installer
* @returns {Promise} * @returns {Promise}
*/ */
function updateUserConfigMac(globalConfigPath) { function updateUserConfigMac() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const userConfigFile = path.join(dirs.userConfig(), configFileName); const userConfigFile = path.join(dirs.userConfig(), configFileName);
// if user config file does't exists just copy global config file // if user config file does't exist, just use the global config settings
// i.e. until an user makes changes manually using the menu items
if (!fs.existsSync(userConfigFile)) { if (!fs.existsSync(userConfigFile)) {
resolve(copyConfigMac(globalConfigPath)); log.send(logLevels.WARN, 'config: Could not find the user config file!');
reject();
return; return;
} }
Promise.all([readGlobalConfig(), readUserConfig(userConfigFile)]) // In case the file exists, we remove it so that all the
.then((data) => { // values are fetched from the global config
resolve(updateUserConfig(data[0], data[1])); // https://perzoinc.atlassian.net/browse/ELECTRON-126
}) readUserConfig(userConfigFile).then((data) => {
.catch((err) => { resolve(updateUserConfig(data));
reject(err); }).catch((err) => {
}); reject(err);
});
}
/**
* Method to copy global config file to user config directory for Windows
* @returns {Promise}
*/
function copyConfigWin() {
return new Promise((resolve, reject) => {
const globalConfigFileName = path.join('config', configFileName);
const execPath = path.dirname(app.getPath('exe'));
const globalConfigPath = path.join(execPath, '', globalConfigFileName);
const userConfigPath = app.getPath('userData');
childProcess.exec(`echo D|xcopy /y /e /s /c "${globalConfigPath}" "${userConfigPath}"`, { timeout: 60000 }, (err) => {
if (err) {
reject(err);
return;
}
resolve();
}); });
});
}
/**
* Method which copies global config file to user config directory for mac
* @param {String} globalConfigPath - The global config path from installer
* @returns {Promise}
*/
function copyConfigMac(globalConfigPath) {
return new Promise((resolve, reject) => {
let userConfigPath = dirs.userConfig() + '/';
let userName = process.env.USER;
childProcess.exec(`rsync -r "${globalConfigPath}" "${userConfigPath}" && chown -R "${userName}" "${userConfigPath}"`, { timeout: 60000 }, (err) => {
if (err) {
reject(err);
return;
}
resolve();
});
}); });
} }
@ -349,13 +323,17 @@ function clearCachedConfigs() {
} }
module.exports = { module.exports = {
getConfigField,
updateConfigField,
configFileName, configFileName,
getConfigField,
updateConfigField,
updateUserConfigWin, updateUserConfigWin,
updateUserConfigMac, updateUserConfigMac,
// items below here are only exported for testing, do NOT use! // items below here are only exported for testing, do NOT use!
saveUserConfig, saveUserConfig,
clearCachedConfigs clearCachedConfigs
}; };

View File

@ -8,13 +8,8 @@ const squirrelStartup = require('electron-squirrel-startup');
const AutoLaunch = require('auto-launch'); const AutoLaunch = require('auto-launch');
const urlParser = require('url'); const urlParser = require('url');
const childProcess = require('child_process');
const path = require('path');
const AppDirectory = require('appdirectory');
const dirs = new AppDirectory('Symphony');
// Local Dependencies // Local Dependencies
const { getConfigField } = require('./config.js'); const {getConfigField, updateUserConfigWin, updateUserConfigMac} = require('./config.js');
const { isMac, isDevEnv } = require('./utils/misc.js'); const { isMac, isDevEnv } = require('./utils/misc.js');
const protocolHandler = require('./protocolHandler'); const protocolHandler = require('./protocolHandler');
const getCmdLineArg = require('./utils/getCmdLineArg.js'); const getCmdLineArg = require('./utils/getCmdLineArg.js');
@ -122,8 +117,7 @@ function setupThenOpenMainWindow() {
isAppAlreadyOpen = true; isAppAlreadyOpen = true;
// allows installer to launch app and set auto startup mode then // allows installer to launch app and set appropriate global / user config params.
// immediately quit.
let hasInstallFlag = getCmdLineArg(process.argv, '--install', true); let hasInstallFlag = getCmdLineArg(process.argv, '--install', true);
let perUserInstall = getCmdLineArg(process.argv, '--peruser', true); let perUserInstall = getCmdLineArg(process.argv, '--peruser', true);
if (!isMac && hasInstallFlag) { if (!isMac && hasInstallFlag) {
@ -178,43 +172,6 @@ function setStartup(lStartup) {
}); });
} }
/**
* Method to overwrite user config on mac installer
* @returns {Promise}
*/
function updateUserConfigMac() {
return new Promise((resolve, reject) => {
let userConfigPath = dirs.userConfig() + '/';
let globalConfigPath = process.argv[2];
let userName = process.env.USER;
childProcess.exec(`rsync -r "${globalConfigPath}" "${userConfigPath}" && chown -R "${userName}" "${userConfigPath}"`, {timeout: 60000}, (err) => {
if (err) {
reject(err);
}
resolve();
});
});
}
/**
* Method to overwrite user config on windows installer
* @returns {Promise}
*/
function updateUserConfigWin() {
return new Promise((resolve, reject) => {
let userConfigPath = app.getPath('userData');
let globalConfigPath = path.join(__dirname, '..', '..', '..', 'config/Symphony.config');
childProcess.exec(`echo D|xcopy /y /e /s /c "${globalConfigPath}" "${userConfigPath}"`, {timeout: 60000}, (err) => {
if (err) {
reject(err);
}
resolve();
});
});
}
/** /**
* Checks for the url argument, processes it * Checks for the url argument, processes it
* and creates the main window * and creates the main window

View File

@ -40,8 +40,6 @@ document.addEventListener('DOMContentLoaded', () => {
} }
}); });
const nodeURL = require('url');
// hold ref so doesn't get GC'ed // hold ref so doesn't get GC'ed
const local = { const local = {
ipcRenderer: ipcRenderer ipcRenderer: ipcRenderer

10
package-lock.json generated
View File

@ -2392,6 +2392,11 @@
} }
} }
}, },
"electron-log": {
"version": "2.2.9",
"resolved": "https://registry.npmjs.org/electron-log/-/electron-log-2.2.9.tgz",
"integrity": "sha512-WNMSipQYurNxY14RO6IKgcxcZg1e4aNVpUUJK9q7Bqe0TZEKn1e5h4HiQKhTgVLqKrUn++ugOZrty450P9vpjA=="
},
"electron-macos-sign": { "electron-macos-sign": {
"version": "1.6.0", "version": "1.6.0",
"resolved": "https://registry.npmjs.org/electron-macos-sign/-/electron-macos-sign-1.6.0.tgz", "resolved": "https://registry.npmjs.org/electron-macos-sign/-/electron-macos-sign-1.6.0.tgz",
@ -5147,6 +5152,11 @@
"integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=", "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=",
"dev": true "dev": true
}, },
"lodash.omit": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz",
"integrity": "sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA="
},
"lodash.toarray": { "lodash.toarray": {
"version": "4.4.0", "version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz",

View File

@ -103,7 +103,7 @@
"electron-squirrel-startup": "^1.0.0", "electron-squirrel-startup": "^1.0.0",
"filesize": "^3.5.10", "filesize": "^3.5.10",
"keymirror": "0.1.1", "keymirror": "0.1.1",
"lodash.pick": "^4.4.0", "lodash.omit": "^4.5.0",
"winreg": "^1.2.3" "winreg": "^1.2.3"
}, },
"optionalDependencies": { "optionalDependencies": {