mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-11 18:48:33 -05:00
Merge from master
This commit is contained in:
@@ -3,9 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import 'vs/code/electron-main/contributions';
|
||||
import 'vs/code/code.main';
|
||||
import { app, dialog } from 'electron';
|
||||
import { assign } from 'vs/base/common/objects';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
@@ -16,10 +14,9 @@ import { mkdirp, readdir, rimraf } from 'vs/base/node/pfs';
|
||||
import { validatePaths } from 'vs/code/node/paths';
|
||||
import { LifecycleService, ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain';
|
||||
import { Server, serve, connect } from 'vs/base/parts/ipc/node/ipc.net';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { ILaunchChannel, LaunchChannelClient } from 'vs/code/electron-main/launch';
|
||||
import { LaunchChannelClient } from 'vs/platform/launch/electron-main/launchService';
|
||||
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||
import { InstantiationService } from 'vs/platform/instantiation/node/instantiationService';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { ILogService, ConsoleLogMainService, MultiplexLogService, getLogLevel } from 'vs/platform/log/common/log';
|
||||
@@ -44,29 +41,26 @@ import { IWorkspacesMainService } from 'vs/platform/workspaces/common/workspaces
|
||||
import { localize } from 'vs/nls';
|
||||
import { mnemonicButtonLabel } from 'vs/base/common/labels';
|
||||
import { createSpdLogService } from 'vs/platform/log/node/spdlogService';
|
||||
import { printDiagnostics } from 'vs/code/electron-main/diagnostics';
|
||||
import { IDiagnosticsService, DiagnosticsService } from 'vs/platform/diagnostics/electron-main/diagnosticsService';
|
||||
import { BufferLogService } from 'vs/platform/log/common/bufferLog';
|
||||
import { uploadLogs } from 'vs/code/electron-main/logUploader';
|
||||
import { setUnexpectedErrorHandler } from 'vs/base/common/errors';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { CommandLineDialogService } from 'vs/platform/dialogs/node/dialogService';
|
||||
import { IUriDisplayService, UriDisplayService } from 'vs/platform/uriDisplay/common/uriDisplay';
|
||||
import { ILabelService, LabelService } from 'vs/platform/label/common/label';
|
||||
import { createWaitMarkerFile } from 'vs/code/node/wait';
|
||||
|
||||
function createServices(args: ParsedArgs, bufferLogService: BufferLogService): IInstantiationService {
|
||||
const services = new ServiceCollection();
|
||||
|
||||
const environmentService = new EnvironmentService(args, process.execPath);
|
||||
const consoleLogService = new ConsoleLogMainService(getLogLevel(environmentService));
|
||||
const logService = new MultiplexLogService([consoleLogService, bufferLogService]);
|
||||
const uriDisplayService = new UriDisplayService(environmentService, undefined);
|
||||
|
||||
const logService = new MultiplexLogService([new ConsoleLogMainService(getLogLevel(environmentService)), bufferLogService]);
|
||||
process.once('exit', () => logService.dispose());
|
||||
|
||||
// Eventually cleanup
|
||||
setTimeout(() => cleanupOlderLogs(environmentService).then(null, err => console.error(err)), 10000);
|
||||
|
||||
services.set(IEnvironmentService, environmentService);
|
||||
services.set(IUriDisplayService, uriDisplayService);
|
||||
services.set(ILabelService, new LabelService(environmentService, void 0, void 0));
|
||||
services.set(ILogService, logService);
|
||||
services.set(IWorkspacesMainService, new SyncDescriptor(WorkspacesMainService));
|
||||
services.set(IHistoryMainService, new SyncDescriptor(HistoryMainService));
|
||||
@@ -77,6 +71,7 @@ function createServices(args: ParsedArgs, bufferLogService: BufferLogService): I
|
||||
services.set(IURLService, new SyncDescriptor(URLService));
|
||||
services.set(IBackupMainService, new SyncDescriptor(BackupMainService));
|
||||
services.set(IDialogService, new SyncDescriptor(CommandLineDialogService));
|
||||
services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService));
|
||||
|
||||
return new InstantiationService(services, true);
|
||||
}
|
||||
@@ -92,31 +87,33 @@ async function cleanupOlderLogs(environmentService: EnvironmentService): Promise
|
||||
const oldSessions = allSessions.sort().filter((d, i) => d !== currentLog);
|
||||
const toDelete = oldSessions.slice(0, Math.max(0, oldSessions.length - 9));
|
||||
|
||||
await TPromise.join(toDelete.map(name => rimraf(path.join(logsRoot, name))));
|
||||
await Promise.all(toDelete.map(name => rimraf(path.join(logsRoot, name))));
|
||||
}
|
||||
|
||||
function createPaths(environmentService: IEnvironmentService): TPromise<any> {
|
||||
function createPaths(environmentService: IEnvironmentService): Thenable<any> {
|
||||
const paths = [
|
||||
environmentService.appSettingsHome,
|
||||
environmentService.extensionsPath,
|
||||
environmentService.nodeCachedDataDir,
|
||||
environmentService.logsPath
|
||||
environmentService.logsPath,
|
||||
environmentService.globalStorageHome,
|
||||
environmentService.workspaceStorageHome
|
||||
];
|
||||
|
||||
return TPromise.join(paths.map(p => p && mkdirp(p))) as TPromise<any>;
|
||||
return Promise.all(paths.map(path => path && mkdirp(path)));
|
||||
}
|
||||
|
||||
class ExpectedError extends Error {
|
||||
public readonly isExpected = true;
|
||||
}
|
||||
|
||||
function setupIPC(accessor: ServicesAccessor): TPromise<Server> {
|
||||
function setupIPC(accessor: ServicesAccessor): Thenable<Server> {
|
||||
const logService = accessor.get(ILogService);
|
||||
const environmentService = accessor.get(IEnvironmentService);
|
||||
const requestService = accessor.get(IRequestService);
|
||||
const diagnosticsService = accessor.get(IDiagnosticsService);
|
||||
|
||||
function allowSetForegroundWindow(service: LaunchChannelClient): TPromise<void> {
|
||||
let promise = TPromise.wrap<void>(void 0);
|
||||
function allowSetForegroundWindow(service: LaunchChannelClient): Thenable<void> {
|
||||
let promise: Thenable<void> = Promise.resolve();
|
||||
if (platform.isWindows) {
|
||||
promise = service.getMainProcessId()
|
||||
.then(processId => {
|
||||
@@ -134,7 +131,7 @@ function setupIPC(accessor: ServicesAccessor): TPromise<Server> {
|
||||
return promise;
|
||||
}
|
||||
|
||||
function setup(retry: boolean): TPromise<Server> {
|
||||
function setup(retry: boolean): Thenable<Server> {
|
||||
return serve(environmentService.mainIPCHandle).then(server => {
|
||||
|
||||
// Print --status usage info
|
||||
@@ -161,7 +158,7 @@ function setupIPC(accessor: ServicesAccessor): TPromise<Server> {
|
||||
return server;
|
||||
}, err => {
|
||||
if (err.code !== 'EADDRINUSE') {
|
||||
return TPromise.wrapError<Server>(err);
|
||||
return Promise.reject<Server>(err);
|
||||
}
|
||||
|
||||
// Since we are the second instance, we do not want to show the dock
|
||||
@@ -179,13 +176,13 @@ function setupIPC(accessor: ServicesAccessor): TPromise<Server> {
|
||||
logService.error(msg);
|
||||
client.dispose();
|
||||
|
||||
return TPromise.wrapError<Server>(new Error(msg));
|
||||
return Promise.reject(new Error(msg));
|
||||
}
|
||||
|
||||
// Show a warning dialog after some timeout if it takes long to talk to the other instance
|
||||
// Skip this if we are running with --wait where it is expected that we wait for a while.
|
||||
// Also skip when gathering diagnostics (--status) which can take a longer time.
|
||||
let startupWarningDialogHandle: number;
|
||||
let startupWarningDialogHandle: any;
|
||||
if (!environmentService.wait && !environmentService.status && !environmentService.args['upload-logs']) {
|
||||
startupWarningDialogHandle = setTimeout(() => {
|
||||
showStartupWarningDialog(
|
||||
@@ -195,20 +192,20 @@ function setupIPC(accessor: ServicesAccessor): TPromise<Server> {
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
const channel = client.getChannel<ILaunchChannel>('launch');
|
||||
const channel = client.getChannel('launch');
|
||||
const service = new LaunchChannelClient(channel);
|
||||
|
||||
// Process Info
|
||||
if (environmentService.args.status) {
|
||||
return service.getMainProcessInfo().then(info => {
|
||||
return printDiagnostics(info).then(() => TPromise.wrapError(new ExpectedError()));
|
||||
return diagnosticsService.printDiagnostics(info).then(() => Promise.reject(new ExpectedError()));
|
||||
});
|
||||
}
|
||||
|
||||
// Log uploader
|
||||
if (typeof environmentService.args['upload-logs'] !== 'undefined') {
|
||||
return uploadLogs(channel, requestService, environmentService)
|
||||
.then(() => TPromise.wrapError(new ExpectedError()));
|
||||
return uploadLogs(service, requestService, environmentService)
|
||||
.then(() => Promise.reject(new ExpectedError()));
|
||||
}
|
||||
|
||||
logService.trace('Sending env to running instance...');
|
||||
@@ -223,7 +220,7 @@ function setupIPC(accessor: ServicesAccessor): TPromise<Server> {
|
||||
clearTimeout(startupWarningDialogHandle);
|
||||
}
|
||||
|
||||
return TPromise.wrapError(new ExpectedError('Sent env to running instance. Terminating...'));
|
||||
return Promise.reject(new ExpectedError('Sent env to running instance. Terminating...'));
|
||||
});
|
||||
},
|
||||
err => {
|
||||
@@ -235,7 +232,7 @@ function setupIPC(accessor: ServicesAccessor): TPromise<Server> {
|
||||
);
|
||||
}
|
||||
|
||||
return TPromise.wrapError<Server>(err);
|
||||
return Promise.reject<Server>(err);
|
||||
}
|
||||
|
||||
// it happens on Linux and OS X that the pipe is left behind
|
||||
@@ -245,7 +242,7 @@ function setupIPC(accessor: ServicesAccessor): TPromise<Server> {
|
||||
fs.unlinkSync(environmentService.mainIPCHandle);
|
||||
} catch (e) {
|
||||
logService.warn('Could not delete obsolete instance handle', e);
|
||||
return TPromise.wrapError<Server>(e);
|
||||
return Promise.reject<Server>(e);
|
||||
}
|
||||
|
||||
return setup(false);
|
||||
@@ -293,12 +290,55 @@ function quit(accessor: ServicesAccessor, reason?: ExpectedError | Error): void
|
||||
lifecycleService.kill(exitCode);
|
||||
}
|
||||
|
||||
function main() {
|
||||
function patchEnvironment(environmentService: IEnvironmentService): typeof process.env {
|
||||
const instanceEnvironment: typeof process.env = {
|
||||
VSCODE_IPC_HOOK: environmentService.mainIPCHandle,
|
||||
VSCODE_NLS_CONFIG: process.env['VSCODE_NLS_CONFIG'],
|
||||
VSCODE_LOGS: process.env['VSCODE_LOGS']
|
||||
};
|
||||
|
||||
if (process.env['VSCODE_PORTABLE']) {
|
||||
instanceEnvironment['VSCODE_PORTABLE'] = process.env['VSCODE_PORTABLE'];
|
||||
}
|
||||
|
||||
assign(process.env, instanceEnvironment);
|
||||
|
||||
return instanceEnvironment;
|
||||
}
|
||||
|
||||
function startup(args: ParsedArgs): void {
|
||||
|
||||
// We need to buffer the spdlog logs until we are sure
|
||||
// we are the only instance running, otherwise we'll have concurrent
|
||||
// log file access on Windows (https://github.com/Microsoft/vscode/issues/41218)
|
||||
const bufferLogService = new BufferLogService();
|
||||
|
||||
const instantiationService = createServices(args, bufferLogService);
|
||||
instantiationService.invokeFunction(accessor => {
|
||||
const environmentService = accessor.get(IEnvironmentService);
|
||||
|
||||
// Patch `process.env` with the instance's environment
|
||||
const instanceEnvironment = patchEnvironment(environmentService);
|
||||
|
||||
// Startup
|
||||
return instantiationService
|
||||
.invokeFunction(a => createPaths(a.get(IEnvironmentService)))
|
||||
.then(() => instantiationService.invokeFunction(setupIPC))
|
||||
.then(mainIpcServer => {
|
||||
bufferLogService.logger = createSpdLogService('main', bufferLogService.getLevel(), environmentService.logsPath);
|
||||
|
||||
return instantiationService.createInstance(CodeApplication, mainIpcServer, instanceEnvironment).startup();
|
||||
});
|
||||
}).then(null, err => instantiationService.invokeFunction(quit, err));
|
||||
}
|
||||
|
||||
function main(): void {
|
||||
|
||||
// Set the error handler early enough so that we are not getting the
|
||||
// default electron error dialog popping up
|
||||
setUnexpectedErrorHandler(err => console.error(err));
|
||||
|
||||
// Parse arguments
|
||||
let args: ParsedArgs;
|
||||
try {
|
||||
args = parseMainProcessArgv(process.argv);
|
||||
@@ -307,40 +347,31 @@ function main() {
|
||||
console.error(err.message);
|
||||
app.exit(1);
|
||||
|
||||
return;
|
||||
return void 0;
|
||||
}
|
||||
|
||||
// We need to buffer the spdlog logs until we are sure
|
||||
// we are the only instance running, otherwise we'll have concurrent
|
||||
// log file access on Windows
|
||||
// https://github.com/Microsoft/vscode/issues/41218
|
||||
const bufferLogService = new BufferLogService();
|
||||
const instantiationService = createServices(args, bufferLogService);
|
||||
// If we are started with --wait create a random temporary file
|
||||
// and pass it over to the starting instance. We can use this file
|
||||
// to wait for it to be deleted to monitor that the edited file
|
||||
// is closed and then exit the waiting process.
|
||||
//
|
||||
// Note: we are not doing this if the wait marker has been already
|
||||
// added as argument. This can happen if Code was started from CLI.
|
||||
if (args.wait && !args.waitMarkerFilePath) {
|
||||
createWaitMarkerFile(args.verbose).then(waitMarkerFilePath => {
|
||||
if (waitMarkerFilePath) {
|
||||
process.argv.push('--waitMarkerFilePath', waitMarkerFilePath);
|
||||
args.waitMarkerFilePath = waitMarkerFilePath;
|
||||
}
|
||||
|
||||
return instantiationService.invokeFunction(accessor => {
|
||||
startup(args);
|
||||
});
|
||||
}
|
||||
|
||||
// Patch `process.env` with the instance's environment
|
||||
const environmentService = accessor.get(IEnvironmentService);
|
||||
const instanceEnv: typeof process.env = {
|
||||
VSCODE_IPC_HOOK: environmentService.mainIPCHandle,
|
||||
VSCODE_NLS_CONFIG: process.env['VSCODE_NLS_CONFIG'],
|
||||
VSCODE_LOGS: process.env['VSCODE_LOGS']
|
||||
};
|
||||
|
||||
if (process.env['VSCODE_PORTABLE']) {
|
||||
instanceEnv['VSCODE_PORTABLE'] = process.env['VSCODE_PORTABLE'];
|
||||
}
|
||||
|
||||
assign(process.env, instanceEnv);
|
||||
|
||||
// Startup
|
||||
return instantiationService.invokeFunction(a => createPaths(a.get(IEnvironmentService)))
|
||||
.then(() => instantiationService.invokeFunction(setupIPC))
|
||||
.then(mainIpcServer => {
|
||||
bufferLogService.logger = createSpdLogService('main', bufferLogService.getLevel(), environmentService.logsPath);
|
||||
return instantiationService.createInstance(CodeApplication, mainIpcServer, instanceEnv).startup();
|
||||
});
|
||||
}).done(null, err => instantiationService.invokeFunction(quit, err));
|
||||
// Otherwise just startup normally
|
||||
else {
|
||||
startup(args);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
Reference in New Issue
Block a user