portable mode
This commit is contained in:
commit
e43ab4e4c4
33
src/cli.js
33
src/cli.js
|
@ -3,6 +3,39 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
Error.stackTraceLimit = 100; // increase number of stack frames (from 10, https://github.com/v8/v8/wiki/Stack-Trace-API)
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const product = require('../product.json');
|
||||||
|
const appRoot = path.dirname(__dirname);
|
||||||
|
|
||||||
|
function getApplicationPath() {
|
||||||
|
if (process.env['VSCODE_DEV']) {
|
||||||
|
return appRoot;
|
||||||
|
} else if (process.platform === 'darwin') {
|
||||||
|
return path.dirname(path.dirname(path.dirname(appRoot)));
|
||||||
|
} else {
|
||||||
|
return path.dirname(path.dirname(appRoot));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const portableDataName = product.portable || `${product.applicationName}-portable-data`;
|
||||||
|
const portableDataPath = path.join(path.dirname(getApplicationPath()), portableDataName);
|
||||||
|
const isPortable = fs.existsSync(portableDataPath);
|
||||||
|
const portableTempPath = path.join(portableDataPath, 'tmp');
|
||||||
|
const isTempPortable = isPortable && fs.existsSync(portableTempPath);
|
||||||
|
|
||||||
|
if (isPortable) {
|
||||||
|
process.env['VSCODE_PORTABLE'] = portableDataPath;
|
||||||
|
} else {
|
||||||
|
delete process.env['VSCODE_PORTABLE'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTempPortable) {
|
||||||
|
process.env[process.platform === 'win32' ? 'TEMP' : 'TMPDIR'] = portableTempPath;
|
||||||
|
}
|
||||||
|
|
||||||
//#region Add support for using node_modules.asar
|
//#region Add support for using node_modules.asar
|
||||||
(function () {
|
(function () {
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
184
src/main.js
184
src/main.js
|
@ -4,7 +4,7 @@
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
let perf = require('./vs/base/common/performance');
|
const perf = require('./vs/base/common/performance');
|
||||||
perf.mark('main:started');
|
perf.mark('main:started');
|
||||||
|
|
||||||
// Perf measurements
|
// Perf measurements
|
||||||
|
@ -12,6 +12,37 @@ global.perfStartTime = Date.now();
|
||||||
|
|
||||||
Error.stackTraceLimit = 100; // increase number of stack frames (from 10, https://github.com/v8/v8/wiki/Stack-Trace-API)
|
Error.stackTraceLimit = 100; // increase number of stack frames (from 10, https://github.com/v8/v8/wiki/Stack-Trace-API)
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const product = require('../product.json');
|
||||||
|
const appRoot = path.dirname(__dirname);
|
||||||
|
|
||||||
|
function getApplicationPath() {
|
||||||
|
if (process.env['VSCODE_DEV']) {
|
||||||
|
return appRoot;
|
||||||
|
} else if (process.platform === 'darwin') {
|
||||||
|
return path.dirname(path.dirname(path.dirname(appRoot)));
|
||||||
|
} else {
|
||||||
|
return path.dirname(path.dirname(appRoot));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const portableDataName = product.portable || `${product.applicationName}-portable-data`;
|
||||||
|
const portableDataPath = process.env['VSCODE_PORTABLE'] || path.join(path.dirname(getApplicationPath()), portableDataName);
|
||||||
|
const isPortable = fs.existsSync(portableDataPath);
|
||||||
|
const portableTempPath = path.join(portableDataPath, 'tmp');
|
||||||
|
const isTempPortable = isPortable && fs.existsSync(portableTempPath);
|
||||||
|
|
||||||
|
if (isPortable) {
|
||||||
|
process.env['VSCODE_PORTABLE'] = portableDataPath;
|
||||||
|
} else {
|
||||||
|
delete process.env['VSCODE_PORTABLE'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTempPortable) {
|
||||||
|
process.env[process.platform === 'win32' ? 'TEMP' : 'TMPDIR'] = portableTempPath;
|
||||||
|
}
|
||||||
|
|
||||||
//#region Add support for using node_modules.asar
|
//#region Add support for using node_modules.asar
|
||||||
(function () {
|
(function () {
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
@ -36,7 +67,7 @@ Error.stackTraceLimit = 100; // increase number of stack frames (from 10, https:
|
||||||
})();
|
})();
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
let app = require('electron').app;
|
const app = require('electron').app;
|
||||||
|
|
||||||
// TODO@Ben Electron 2.0.x: prevent localStorage migration from SQLite to LevelDB due to issues
|
// TODO@Ben Electron 2.0.x: prevent localStorage migration from SQLite to LevelDB due to issues
|
||||||
app.commandLine.appendSwitch('disable-mojo-local-storage');
|
app.commandLine.appendSwitch('disable-mojo-local-storage');
|
||||||
|
@ -44,15 +75,19 @@ app.commandLine.appendSwitch('disable-mojo-local-storage');
|
||||||
// TODO@Ben Electron 2.0.x: force srgb color profile (for https://github.com/Microsoft/vscode/issues/51791)
|
// TODO@Ben Electron 2.0.x: force srgb color profile (for https://github.com/Microsoft/vscode/issues/51791)
|
||||||
app.commandLine.appendSwitch('force-color-profile', 'srgb');
|
app.commandLine.appendSwitch('force-color-profile', 'srgb');
|
||||||
|
|
||||||
let fs = require('fs');
|
const minimist = require('minimist');
|
||||||
let path = require('path');
|
const paths = require('./paths');
|
||||||
let minimist = require('minimist');
|
|
||||||
let paths = require('./paths');
|
|
||||||
|
|
||||||
let args = minimist(process.argv, {
|
const args = minimist(process.argv, {
|
||||||
string: ['user-data-dir', 'locale']
|
string: [
|
||||||
|
'user-data-dir',
|
||||||
|
'locale',
|
||||||
|
'js-flags',
|
||||||
|
'max-memory'
|
||||||
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//#region NLS
|
||||||
function stripComments(content) {
|
function stripComments(content) {
|
||||||
let regexp = /("(?:[^\\\"]*(?:\\.)?)*")|('(?:[^\\\']*(?:\\.)?)*')|(\/\*(?:\r?\n|.)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))/g;
|
let regexp = /("(?:[^\\\"]*(?:\\.)?)*")|('(?:[^\\\']*(?:\\.)?)*')|(\/\*(?:\r?\n|.)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))/g;
|
||||||
let result = content.replace(regexp, function (match, m1, m2, m3, m4) {
|
let result = content.replace(regexp, function (match, m1, m2, m3, m4) {
|
||||||
|
@ -77,113 +112,38 @@ function stripComments(content) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
let _commit;
|
const mkdir = dir => new Promise((c, e) => fs.mkdir(dir, err => (err && err.code !== 'EEXIST') ? e(err) : c()));
|
||||||
function getCommit() {
|
const exists = file => new Promise(c => fs.exists(file, c));
|
||||||
if (_commit) {
|
const readFile = file => new Promise((c, e) => fs.readFile(file, 'utf8', (err, data) => err ? e(err) : c(data)));
|
||||||
return _commit;
|
const writeFile = (file, content) => new Promise((c, e) => fs.writeFile(file, content, 'utf8', err => err ? e(err) : c()));
|
||||||
}
|
const touch = file => new Promise((c, e) => { const d = new Date(); fs.utimes(file, d, d, err => err ? e(err) : c()); });
|
||||||
if (_commit === null) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
let productJson = require(path.join(__dirname, '../product.json'));
|
|
||||||
if (productJson.commit) {
|
|
||||||
_commit = productJson.commit;
|
|
||||||
} else {
|
|
||||||
_commit = null;
|
|
||||||
}
|
|
||||||
} catch (exp) {
|
|
||||||
_commit = null;
|
|
||||||
}
|
|
||||||
return _commit || undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
function mkdirp(dir) {
|
function mkdirp(dir) {
|
||||||
return mkdir(dir)
|
return mkdir(dir).then(null, err => {
|
||||||
.then(null, (err) => {
|
if (err && err.code === 'ENOENT') {
|
||||||
if (err && err.code === 'ENOENT') {
|
const parent = path.dirname(dir);
|
||||||
let parent = path.dirname(dir);
|
|
||||||
if (parent !== dir) { // if not arrived at root
|
|
||||||
return mkdirp(parent)
|
|
||||||
.then(() => {
|
|
||||||
return mkdir(dir);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw err;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function mkdir(dir) {
|
if (parent !== dir) { // if not arrived at root
|
||||||
return new Promise((resolve, reject) => {
|
return mkdirp(parent).then(() => mkdir(dir));
|
||||||
fs.mkdir(dir, (err) => {
|
|
||||||
if (err && err.code !== 'EEXIST') {
|
|
||||||
reject(err);
|
|
||||||
} else {
|
|
||||||
resolve(dir);
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function exists(file) {
|
throw err;
|
||||||
return new Promise((resolve) => {
|
|
||||||
fs.exists(file, (result) => {
|
|
||||||
resolve(result);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function readFile(file) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
fs.readFile(file, 'utf8', (err, data) => {
|
|
||||||
if (err) {
|
|
||||||
reject(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resolve(data);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeFile(file, content) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
fs.writeFile(file, content, 'utf8', (err) => {
|
|
||||||
if (err) {
|
|
||||||
reject(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resolve(undefined);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function touch(file) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let d = new Date();
|
|
||||||
fs.utimes(file, d, d, (err) => {
|
|
||||||
if (err) {
|
|
||||||
reject(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resolve(undefined);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveJSFlags() {
|
function resolveJSFlags() {
|
||||||
let jsFlags = [];
|
const jsFlags = [];
|
||||||
|
|
||||||
if (args['js-flags']) {
|
if (args['js-flags']) {
|
||||||
jsFlags.push(args['js-flags']);
|
jsFlags.push(args['js-flags']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args['max-memory'] && !/max_old_space_size=(\d+)/g.exec(args['js-flags'])) {
|
if (args['max-memory'] && !/max_old_space_size=(\d+)/g.exec(args['js-flags'])) {
|
||||||
jsFlags.push(`--max_old_space_size=${args['max-memory']}`);
|
jsFlags.push(`--max_old_space_size=${args['max-memory']}`);
|
||||||
}
|
}
|
||||||
if (jsFlags.length > 0) {
|
|
||||||
return jsFlags.join(' ');
|
return jsFlags.length > 0 ? jsFlags.join(' ') : null;
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Language tags are case insensitve however an amd loader is case sensitive
|
// Language tags are case insensitve however an amd loader is case sensitive
|
||||||
|
@ -288,7 +248,7 @@ function getNLSConfiguration(locale) {
|
||||||
}
|
}
|
||||||
|
|
||||||
perf.mark('nlsGeneration:start');
|
perf.mark('nlsGeneration:start');
|
||||||
let defaultResult = function(locale) {
|
let defaultResult = function (locale) {
|
||||||
let isCoreLanguage = true;
|
let isCoreLanguage = true;
|
||||||
if (locale) {
|
if (locale) {
|
||||||
isCoreLanguage = ['de', 'es', 'fr', 'it', 'ja', 'ko', 'ru', 'zh-cn', 'zh-tw'].some((language) => {
|
isCoreLanguage = ['de', 'es', 'fr', 'it', 'ja', 'ko', 'ru', 'zh-cn', 'zh-tw'].some((language) => {
|
||||||
|
@ -299,13 +259,13 @@ function getNLSConfiguration(locale) {
|
||||||
let result = resolveLocale(locale);
|
let result = resolveLocale(locale);
|
||||||
perf.mark('nlsGeneration:end');
|
perf.mark('nlsGeneration:end');
|
||||||
return Promise.resolve(result);
|
return Promise.resolve(result);
|
||||||
} else {
|
} else {
|
||||||
perf.mark('nlsGeneration:end');
|
perf.mark('nlsGeneration:end');
|
||||||
return Promise.resolve({ locale: locale, availableLanguages: {} });
|
return Promise.resolve({ locale: locale, availableLanguages: {} });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
let commit = getCommit();
|
let commit = product.commit;
|
||||||
if (!commit) {
|
if (!commit) {
|
||||||
return defaultResult(locale);
|
return defaultResult(locale);
|
||||||
}
|
}
|
||||||
|
@ -342,7 +302,7 @@ function getNLSConfiguration(locale) {
|
||||||
return exists(coreLocation).then((fileExists) => {
|
return exists(coreLocation).then((fileExists) => {
|
||||||
if (fileExists) {
|
if (fileExists) {
|
||||||
// We don't wait for this. No big harm if we can't touch
|
// We don't wait for this. No big harm if we can't touch
|
||||||
touch(coreLocation).catch(() => {});
|
touch(coreLocation).catch(() => { });
|
||||||
perf.mark('nlsGeneration:end');
|
perf.mark('nlsGeneration:end');
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -395,7 +355,9 @@ function getNLSConfiguration(locale) {
|
||||||
return defaultResult(locale);
|
return defaultResult(locale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region Cached Data Dir
|
||||||
function getNodeCachedDataDir() {
|
function getNodeCachedDataDir() {
|
||||||
// flag to disable cached data support
|
// flag to disable cached data support
|
||||||
if (process.argv.indexOf('--no-cached-data') > 0) {
|
if (process.argv.indexOf('--no-cached-data') > 0) {
|
||||||
|
@ -408,7 +370,7 @@ function getNodeCachedDataDir() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// find commit id
|
// find commit id
|
||||||
let commit = getCommit();
|
let commit = product.commit;
|
||||||
if (!commit) {
|
if (!commit) {
|
||||||
return Promise.resolve(undefined);
|
return Promise.resolve(undefined);
|
||||||
}
|
}
|
||||||
|
@ -417,10 +379,18 @@ function getNodeCachedDataDir() {
|
||||||
|
|
||||||
return mkdirp(dir).then(undefined, function () { /*ignore*/ });
|
return mkdirp(dir).then(undefined, function () { /*ignore*/ });
|
||||||
}
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
function getUserDataPath() {
|
||||||
|
if (isPortable) {
|
||||||
|
return path.join(portableDataPath, 'user-data');
|
||||||
|
}
|
||||||
|
|
||||||
|
return path.resolve(args['user-data-dir'] || paths.getDefaultUserDataPath(process.platform));
|
||||||
|
}
|
||||||
|
|
||||||
// Set userData path before app 'ready' event and call to process.chdir
|
// Set userData path before app 'ready' event and call to process.chdir
|
||||||
let userData = path.resolve(args['user-data-dir'] || paths.getDefaultUserDataPath(process.platform));
|
app.setPath('userData', getUserDataPath());
|
||||||
app.setPath('userData', userData);
|
|
||||||
|
|
||||||
// Update cwd based on environment and platform
|
// Update cwd based on environment and platform
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -323,6 +323,11 @@ function main() {
|
||||||
VSCODE_NLS_CONFIG: process.env['VSCODE_NLS_CONFIG'],
|
VSCODE_NLS_CONFIG: process.env['VSCODE_NLS_CONFIG'],
|
||||||
VSCODE_LOGS: process.env['VSCODE_LOGS']
|
VSCODE_LOGS: process.env['VSCODE_LOGS']
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (process.env['VSCODE_PORTABLE']) {
|
||||||
|
instanceEnv['VSCODE_PORTABLE'] = process.env['VSCODE_PORTABLE'];
|
||||||
|
}
|
||||||
|
|
||||||
assign(process.env, instanceEnv);
|
assign(process.env, instanceEnv);
|
||||||
|
|
||||||
// Startup
|
// Startup
|
||||||
|
|
|
@ -90,7 +90,13 @@ export class EnvironmentService implements IEnvironmentService {
|
||||||
get userHome(): string { return os.homedir(); }
|
get userHome(): string { return os.homedir(); }
|
||||||
|
|
||||||
@memoize
|
@memoize
|
||||||
get userDataPath(): string { return parseUserDataDir(this._args, process); }
|
get userDataPath(): string {
|
||||||
|
if (process.env['VSCODE_PORTABLE']) {
|
||||||
|
return path.join(process.env['VSCODE_PORTABLE'], 'user-data');
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseUserDataDir(this._args, process);
|
||||||
|
}
|
||||||
|
|
||||||
get appNameLong(): string { return product.nameLong; }
|
get appNameLong(): string { return product.nameLong; }
|
||||||
|
|
||||||
|
@ -127,7 +133,19 @@ export class EnvironmentService implements IEnvironmentService {
|
||||||
get installSourcePath(): string { return path.join(this.userDataPath, 'installSource'); }
|
get installSourcePath(): string { return path.join(this.userDataPath, 'installSource'); }
|
||||||
|
|
||||||
@memoize
|
@memoize
|
||||||
get extensionsPath(): string { return parsePathArg(this._args['extensions-dir'], process) || process.env['VSCODE_EXTENSIONS'] || path.join(this.userHome, product.dataFolderName, 'extensions'); }
|
get extensionsPath(): string {
|
||||||
|
const fromArgs = parsePathArg(this._args['extensions-dir'], process);
|
||||||
|
|
||||||
|
if (fromArgs) {
|
||||||
|
return fromArgs;
|
||||||
|
} else if (process.env['VSCODE_EXTENSIONS']) {
|
||||||
|
return process.env['VSCODE_EXTENSIONS'];
|
||||||
|
} else if (process.env['VSCODE_PORTABLE']) {
|
||||||
|
return path.join(process.env['VSCODE_PORTABLE'], 'extensions');
|
||||||
|
} else {
|
||||||
|
return path.join(this.userHome, product.dataFolderName, 'extensions');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@memoize
|
@memoize
|
||||||
get extensionDevelopmentPath(): string { return this._args.extensionDevelopmentPath ? path.normalize(this._args.extensionDevelopmentPath) : this._args.extensionDevelopmentPath; }
|
get extensionDevelopmentPath(): string { return this._args.extensionDevelopmentPath ? path.normalize(this._args.extensionDevelopmentPath) : this._args.extensionDevelopmentPath; }
|
||||||
|
|
|
@ -73,6 +73,7 @@ export interface IProductConfiguration {
|
||||||
'darwin': string;
|
'darwin': string;
|
||||||
};
|
};
|
||||||
logUploaderUrl: string;
|
logUploaderUrl: string;
|
||||||
|
portable?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISurveyData {
|
export interface ISurveyData {
|
||||||
|
|
|
@ -116,7 +116,8 @@ function cleanEnv() {
|
||||||
'PTYCOLS',
|
'PTYCOLS',
|
||||||
'PTYROWS',
|
'PTYROWS',
|
||||||
'PTYSHELLCMDLINE',
|
'PTYSHELLCMDLINE',
|
||||||
'VSCODE_LOGS'
|
'VSCODE_LOGS',
|
||||||
|
'VSCODE_PORTABLE'
|
||||||
];
|
];
|
||||||
keys.forEach(function (key) {
|
keys.forEach(function (key) {
|
||||||
if (process.env[key]) {
|
if (process.env[key]) {
|
||||||
|
|
Loading…
Reference in a new issue