💄 - introduce CodeMain
This commit is contained in:
parent
bda5098e02
commit
edd560d278
|
@ -358,15 +358,16 @@ export class CodeApplication extends Disposable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async resolveMachineId(): Promise<string> {
|
private async resolveMachineId(): Promise<string> {
|
||||||
|
|
||||||
|
// We cache the machineId for faster lookups on startup
|
||||||
|
// and resolve it only once initially if not cached
|
||||||
let machineId = this.stateService.getItem<string>(CodeApplication.MACHINE_ID_KEY);
|
let machineId = this.stateService.getItem<string>(CodeApplication.MACHINE_ID_KEY);
|
||||||
if (machineId) {
|
if (!machineId) {
|
||||||
return machineId;
|
machineId = await getMachineId();
|
||||||
|
|
||||||
|
this.stateService.setItem(CodeApplication.MACHINE_ID_KEY, machineId);
|
||||||
}
|
}
|
||||||
|
|
||||||
machineId = await getMachineId();
|
|
||||||
|
|
||||||
this.stateService.setItem(CodeApplication.MACHINE_ID_KEY, machineId);
|
|
||||||
|
|
||||||
return machineId;
|
return machineId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,7 +463,6 @@ export class CodeApplication extends Disposable {
|
||||||
this.lifecycleService.onWillShutdown(e => e.join(storageMainService.close()));
|
this.lifecycleService.onWillShutdown(e => e.join(storageMainService.close()));
|
||||||
|
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private initBackupService(accessor: ServicesAccessor): Promise<void> {
|
private initBackupService(accessor: ServicesAccessor): Promise<void> {
|
||||||
|
@ -580,8 +580,8 @@ export class CodeApplication extends Disposable {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mac: open-file event received on startup
|
||||||
if (macOpenFiles && macOpenFiles.length && !hasCliArgs && !hasFolderURIs && !hasFileURIs) {
|
if (macOpenFiles && macOpenFiles.length && !hasCliArgs && !hasFolderURIs && !hasFileURIs) {
|
||||||
// mac: open-file event received on startup
|
|
||||||
return this.windowsMainService.open({
|
return this.windowsMainService.open({
|
||||||
context: OpenContext.DOCK,
|
context: OpenContext.DOCK,
|
||||||
cli: args,
|
cli: args,
|
||||||
|
|
|
@ -44,26 +44,140 @@ class ExpectedError extends Error {
|
||||||
readonly isExpected = true;
|
readonly isExpected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupIPC(accessor: ServicesAccessor): Promise<Server> {
|
class CodeMain {
|
||||||
const logService = accessor.get(ILogService);
|
|
||||||
const environmentService = accessor.get(IEnvironmentService);
|
|
||||||
const instantiationService = accessor.get(IInstantiationService);
|
|
||||||
|
|
||||||
async function windowsAllowSetForegroundWindow(service: LaunchChannelClient): Promise<void> {
|
main(): void {
|
||||||
if (platform.isWindows) {
|
|
||||||
const processId = await service.getMainProcessId();
|
|
||||||
|
|
||||||
logService.trace('Sending some foreground love to the running instance:', processId);
|
// Set the error handler early enough so that we are not getting the
|
||||||
|
// default electron error dialog popping up
|
||||||
|
setUnexpectedErrorHandler(err => console.error(err));
|
||||||
|
|
||||||
try {
|
// Parse arguments
|
||||||
(await import('windows-foreground-love')).allowSetForegroundWindow(processId);
|
let args: ParsedArgs;
|
||||||
} catch (error) {
|
try {
|
||||||
logService.error(error);
|
args = parseMainProcessArgv(process.argv);
|
||||||
|
args = validatePaths(args);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err.message);
|
||||||
|
app.exit(1);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
const waitMarkerFilePath = createWaitMarkerFile(args.verbose);
|
||||||
|
if (waitMarkerFilePath) {
|
||||||
|
addArg(process.argv, '--waitMarkerFilePath', waitMarkerFilePath);
|
||||||
|
args.waitMarkerFilePath = waitMarkerFilePath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Launch
|
||||||
|
this.startup(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async startup(args: ParsedArgs): Promise<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 = this.createServices(args, bufferLogService);
|
||||||
|
try {
|
||||||
|
await instantiationService.invokeFunction(async accessor => {
|
||||||
|
const environmentService = accessor.get(IEnvironmentService);
|
||||||
|
const stateService = accessor.get(IStateService);
|
||||||
|
|
||||||
|
// Patch `process.env` with the instance's environment
|
||||||
|
const instanceEnvironment = this.patchEnvironment(environmentService);
|
||||||
|
|
||||||
|
// Startup
|
||||||
|
try {
|
||||||
|
await this.initServices(environmentService, stateService as StateService);
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
// Show a dialog for errors that can be resolved by the user
|
||||||
|
this.handleStartupDataDirError(environmentService, error);
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mainIpcServer = await instantiationService.invokeFunction(accessor => this.doStartup(accessor, true));
|
||||||
|
bufferLogService.logger = new SpdLogService('main', environmentService.logsPath, bufferLogService.getLevel());
|
||||||
|
|
||||||
|
return instantiationService.createInstance(CodeApplication, mainIpcServer, instanceEnvironment).startup();
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
instantiationService.invokeFunction(this.quit, error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setup(retry: boolean): Promise<Server> {
|
private createServices(args: ParsedArgs, bufferLogService: BufferLogService): IInstantiationService {
|
||||||
|
const services = new ServiceCollection();
|
||||||
|
|
||||||
|
const environmentService = new EnvironmentService(args, process.execPath);
|
||||||
|
|
||||||
|
const logService = new MultiplexLogService([new ConsoleLogMainService(getLogLevel(environmentService)), bufferLogService]);
|
||||||
|
process.once('exit', () => logService.dispose());
|
||||||
|
|
||||||
|
services.set(IEnvironmentService, environmentService);
|
||||||
|
services.set(ILogService, logService);
|
||||||
|
services.set(ILifecycleService, new SyncDescriptor(LifecycleService));
|
||||||
|
services.set(IStateService, new SyncDescriptor(StateService));
|
||||||
|
services.set(IConfigurationService, new SyncDescriptor(ConfigurationService, [environmentService.appSettingsPath]));
|
||||||
|
services.set(IRequestService, new SyncDescriptor(RequestService));
|
||||||
|
services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService));
|
||||||
|
services.set(IThemeMainService, new SyncDescriptor(ThemeMainService));
|
||||||
|
|
||||||
|
return new InstantiationService(services, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private initServices(environmentService: IEnvironmentService, stateService: StateService): Promise<unknown> {
|
||||||
|
|
||||||
|
// Ensure paths for environment service exist
|
||||||
|
const environmentServiceInitialization = Promise.all<void | undefined>([
|
||||||
|
environmentService.extensionsPath,
|
||||||
|
environmentService.nodeCachedDataDir,
|
||||||
|
environmentService.logsPath,
|
||||||
|
environmentService.globalStorageHome,
|
||||||
|
environmentService.workspaceStorageHome,
|
||||||
|
environmentService.backupHome
|
||||||
|
].map((path): undefined | Promise<void> => path ? mkdirp(path) : undefined));
|
||||||
|
|
||||||
|
// State service
|
||||||
|
const stateServiceInitialization = stateService.init();
|
||||||
|
|
||||||
|
return Promise.all([environmentServiceInitialization, stateServiceInitialization]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async doStartup(accessor: ServicesAccessor, retry: boolean): Promise<Server> {
|
||||||
|
const logService = accessor.get(ILogService);
|
||||||
|
const environmentService = accessor.get(IEnvironmentService);
|
||||||
|
const instantiationService = accessor.get(IInstantiationService);
|
||||||
|
|
||||||
// Try to setup a server for running. If that succeeds it means
|
// Try to setup a server for running. If that succeeds it means
|
||||||
// we are the first instance to startup. Otherwise it is likely
|
// we are the first instance to startup. Otherwise it is likely
|
||||||
|
@ -78,7 +192,7 @@ function setupIPC(accessor: ServicesAccessor): Promise<Server> {
|
||||||
if (error.code !== 'EADDRINUSE') {
|
if (error.code !== 'EADDRINUSE') {
|
||||||
|
|
||||||
// Show a dialog for errors that can be resolved by the user
|
// Show a dialog for errors that can be resolved by the user
|
||||||
handleStartupDataDirError(environmentService, error);
|
this.handleStartupDataDirError(environmentService, error);
|
||||||
|
|
||||||
// Any other runtime error is just printed to the console
|
// Any other runtime error is just printed to the console
|
||||||
throw error;
|
throw error;
|
||||||
|
@ -98,7 +212,7 @@ function setupIPC(accessor: ServicesAccessor): Promise<Server> {
|
||||||
// Handle unexpected connection errors by showing a dialog to the user
|
// Handle unexpected connection errors by showing a dialog to the user
|
||||||
if (!retry || platform.isWindows || error.code !== 'ECONNREFUSED') {
|
if (!retry || platform.isWindows || error.code !== 'ECONNREFUSED') {
|
||||||
if (error.code === 'EPERM') {
|
if (error.code === 'EPERM') {
|
||||||
showStartupWarningDialog(
|
this.showStartupWarningDialog(
|
||||||
localize('secondInstanceAdmin', "A second instance of {0} is already running as administrator.", product.nameShort),
|
localize('secondInstanceAdmin', "A second instance of {0} is already running as administrator.", product.nameShort),
|
||||||
localize('secondInstanceAdminDetail', "Please close the other instance and try again.")
|
localize('secondInstanceAdminDetail', "Please close the other instance and try again.")
|
||||||
);
|
);
|
||||||
|
@ -117,7 +231,7 @@ function setupIPC(accessor: ServicesAccessor): Promise<Server> {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return setup(false);
|
return this.doStartup(accessor, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests from CLI require to be the only instance currently
|
// Tests from CLI require to be the only instance currently
|
||||||
|
@ -135,7 +249,7 @@ function setupIPC(accessor: ServicesAccessor): Promise<Server> {
|
||||||
let startupWarningDialogHandle: NodeJS.Timeout | undefined = undefined;
|
let startupWarningDialogHandle: NodeJS.Timeout | undefined = undefined;
|
||||||
if (!environmentService.wait && !environmentService.status && !environmentService.args['upload-logs']) {
|
if (!environmentService.wait && !environmentService.status && !environmentService.args['upload-logs']) {
|
||||||
startupWarningDialogHandle = setTimeout(() => {
|
startupWarningDialogHandle = setTimeout(() => {
|
||||||
showStartupWarningDialog(
|
this.showStartupWarningDialog(
|
||||||
localize('secondInstanceNoResponse', "Another instance of {0} is running but not responding", product.nameShort),
|
localize('secondInstanceNoResponse', "Another instance of {0} is running but not responding", product.nameShort),
|
||||||
localize('secondInstanceNoResponseDetail', "Please close all other instances and try again.")
|
localize('secondInstanceNoResponseDetail', "Please close all other instances and try again.")
|
||||||
);
|
);
|
||||||
|
@ -143,12 +257,12 @@ function setupIPC(accessor: ServicesAccessor): Promise<Server> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const channel = client.getChannel('launch');
|
const channel = client.getChannel('launch');
|
||||||
const service = new LaunchChannelClient(channel);
|
const launchClient = new LaunchChannelClient(channel);
|
||||||
|
|
||||||
// Process Info
|
// Process Info
|
||||||
if (environmentService.args.status) {
|
if (environmentService.args.status) {
|
||||||
return instantiationService.invokeFunction(async accessor => {
|
return instantiationService.invokeFunction(async accessor => {
|
||||||
const diagnostics = await accessor.get(IDiagnosticsService).getDiagnostics(service);
|
const diagnostics = await accessor.get(IDiagnosticsService).getDiagnostics(launchClient);
|
||||||
|
|
||||||
console.log(diagnostics);
|
console.log(diagnostics);
|
||||||
throw new ExpectedError();
|
throw new ExpectedError();
|
||||||
|
@ -158,7 +272,7 @@ function setupIPC(accessor: ServicesAccessor): Promise<Server> {
|
||||||
// Log uploader
|
// Log uploader
|
||||||
if (typeof environmentService.args['upload-logs'] !== 'undefined') {
|
if (typeof environmentService.args['upload-logs'] !== 'undefined') {
|
||||||
return instantiationService.invokeFunction(async accessor => {
|
return instantiationService.invokeFunction(async accessor => {
|
||||||
await uploadLogs(service, accessor.get(IRequestService), environmentService);
|
await uploadLogs(launchClient, accessor.get(IRequestService), environmentService);
|
||||||
|
|
||||||
throw new ExpectedError();
|
throw new ExpectedError();
|
||||||
});
|
});
|
||||||
|
@ -167,12 +281,12 @@ function setupIPC(accessor: ServicesAccessor): Promise<Server> {
|
||||||
|
|
||||||
// Windows: allow to set foreground
|
// Windows: allow to set foreground
|
||||||
if (platform.isWindows) {
|
if (platform.isWindows) {
|
||||||
await windowsAllowSetForegroundWindow(service);
|
await this.windowsAllowSetForegroundWindow(launchClient, logService);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send environment over...
|
// Send environment over...
|
||||||
logService.trace('Sending env to running instance...');
|
logService.trace('Sending env to running instance...');
|
||||||
await service.start(environmentService.args, process.env as platform.IProcessEnvironment);
|
await launchClient.start(environmentService.args, process.env as platform.IProcessEnvironment);
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
await client.dispose();
|
await client.dispose();
|
||||||
|
@ -209,177 +323,66 @@ function setupIPC(accessor: ServicesAccessor): Promise<Server> {
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
return setup(true);
|
private handleStartupDataDirError(environmentService: IEnvironmentService, error: NodeJS.ErrnoException): void {
|
||||||
}
|
if (error.code === 'EACCES' || error.code === 'EPERM') {
|
||||||
|
this.showStartupWarningDialog(
|
||||||
function showStartupWarningDialog(message: string, detail: string): void {
|
localize('startupDataDirError', "Unable to write program user data."),
|
||||||
dialog.showMessageBox({
|
localize('startupDataDirErrorDetail', "Please make sure the directories {0} and {1} are writeable.", environmentService.userDataPath, environmentService.extensionsPath)
|
||||||
title: product.nameLong,
|
);
|
||||||
type: 'warning',
|
|
||||||
buttons: [mnemonicButtonLabel(localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))],
|
|
||||||
message,
|
|
||||||
detail,
|
|
||||||
noLink: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleStartupDataDirError(environmentService: IEnvironmentService, error: NodeJS.ErrnoException): void {
|
|
||||||
if (error.code === 'EACCES' || error.code === 'EPERM') {
|
|
||||||
showStartupWarningDialog(
|
|
||||||
localize('startupDataDirError', "Unable to write program user data."),
|
|
||||||
localize('startupDataDirErrorDetail', "Please make sure the directories {0} and {1} are writeable.", environmentService.userDataPath, environmentService.extensionsPath)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function quit(accessor: ServicesAccessor, reason?: ExpectedError | Error): void {
|
|
||||||
const logService = accessor.get(ILogService);
|
|
||||||
const lifecycleService = accessor.get(ILifecycleService);
|
|
||||||
|
|
||||||
let exitCode = 0;
|
|
||||||
|
|
||||||
if (reason) {
|
|
||||||
if ((reason as ExpectedError).isExpected) {
|
|
||||||
if (reason.message) {
|
|
||||||
logService.trace(reason.message);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
exitCode = 1; // signal error to the outside
|
|
||||||
|
|
||||||
if (reason.stack) {
|
|
||||||
logService.error(reason.stack);
|
|
||||||
} else {
|
|
||||||
logService.error(`Startup error: ${reason.toString()}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lifecycleService.kill(exitCode);
|
private showStartupWarningDialog(message: string, detail: string): void {
|
||||||
}
|
dialog.showMessageBox({
|
||||||
|
title: product.nameLong,
|
||||||
function patchEnvironment(environmentService: IEnvironmentService): typeof process.env {
|
type: 'warning',
|
||||||
const instanceEnvironment: typeof process.env = {
|
buttons: [mnemonicButtonLabel(localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))],
|
||||||
VSCODE_IPC_HOOK: environmentService.mainIPCHandle,
|
message,
|
||||||
VSCODE_NLS_CONFIG: process.env['VSCODE_NLS_CONFIG'],
|
detail,
|
||||||
VSCODE_LOGS: process.env['VSCODE_LOGS']
|
noLink: true
|
||||||
};
|
|
||||||
|
|
||||||
if (process.env['VSCODE_PORTABLE']) {
|
|
||||||
instanceEnvironment['VSCODE_PORTABLE'] = process.env['VSCODE_PORTABLE'];
|
|
||||||
}
|
|
||||||
|
|
||||||
assign(process.env, instanceEnvironment);
|
|
||||||
|
|
||||||
return instanceEnvironment;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function startup(args: ParsedArgs): Promise<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);
|
|
||||||
try {
|
|
||||||
await instantiationService.invokeFunction(async accessor => {
|
|
||||||
const environmentService = accessor.get(IEnvironmentService);
|
|
||||||
const stateService = accessor.get(IStateService);
|
|
||||||
|
|
||||||
// Patch `process.env` with the instance's environment
|
|
||||||
const instanceEnvironment = patchEnvironment(environmentService);
|
|
||||||
|
|
||||||
// Startup
|
|
||||||
try {
|
|
||||||
await initServices(environmentService, stateService as StateService);
|
|
||||||
} catch (error) {
|
|
||||||
|
|
||||||
// Show a dialog for errors that can be resolved by the user
|
|
||||||
handleStartupDataDirError(environmentService, error);
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
const mainIpcServer = await instantiationService.invokeFunction(setupIPC);
|
|
||||||
bufferLogService.logger = new SpdLogService('main', environmentService.logsPath, bufferLogService.getLevel());
|
|
||||||
return instantiationService.createInstance(CodeApplication, mainIpcServer, instanceEnvironment).startup();
|
|
||||||
});
|
});
|
||||||
} catch (error) {
|
|
||||||
instantiationService.invokeFunction(quit, error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createServices(args: ParsedArgs, bufferLogService: BufferLogService): IInstantiationService {
|
|
||||||
const services = new ServiceCollection();
|
|
||||||
|
|
||||||
const environmentService = new EnvironmentService(args, process.execPath);
|
|
||||||
|
|
||||||
const logService = new MultiplexLogService([new ConsoleLogMainService(getLogLevel(environmentService)), bufferLogService]);
|
|
||||||
process.once('exit', () => logService.dispose());
|
|
||||||
|
|
||||||
services.set(IEnvironmentService, environmentService);
|
|
||||||
services.set(ILogService, logService);
|
|
||||||
services.set(ILifecycleService, new SyncDescriptor(LifecycleService));
|
|
||||||
services.set(IStateService, new SyncDescriptor(StateService));
|
|
||||||
services.set(IConfigurationService, new SyncDescriptor(ConfigurationService, [environmentService.appSettingsPath]));
|
|
||||||
services.set(IRequestService, new SyncDescriptor(RequestService));
|
|
||||||
services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService));
|
|
||||||
services.set(IThemeMainService, new SyncDescriptor(ThemeMainService));
|
|
||||||
|
|
||||||
return new InstantiationService(services, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function initServices(environmentService: IEnvironmentService, stateService: StateService): Promise<unknown> {
|
|
||||||
|
|
||||||
// Ensure paths for environment service exist
|
|
||||||
const environmentServiceInitialization = Promise.all<void | undefined>([
|
|
||||||
environmentService.extensionsPath,
|
|
||||||
environmentService.nodeCachedDataDir,
|
|
||||||
environmentService.logsPath,
|
|
||||||
environmentService.globalStorageHome,
|
|
||||||
environmentService.workspaceStorageHome,
|
|
||||||
environmentService.backupHome
|
|
||||||
].map((path): undefined | Promise<void> => path ? mkdirp(path) : undefined));
|
|
||||||
|
|
||||||
// State service
|
|
||||||
const stateServiceInitialization = stateService.init();
|
|
||||||
|
|
||||||
return Promise.all([environmentServiceInitialization, stateServiceInitialization]);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
args = validatePaths(args);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err.message);
|
|
||||||
app.exit(1);
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are started with --wait create a random temporary file
|
private async windowsAllowSetForegroundWindow(client: LaunchChannelClient, logService: ILogService): Promise<void> {
|
||||||
// and pass it over to the starting instance. We can use this file
|
if (platform.isWindows) {
|
||||||
// to wait for it to be deleted to monitor that the edited file
|
const processId = await client.getMainProcessId();
|
||||||
// is closed and then exit the waiting process.
|
|
||||||
//
|
logService.trace('Sending some foreground love to the running instance:', processId);
|
||||||
// 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.
|
try {
|
||||||
if (args.wait && !args.waitMarkerFilePath) {
|
(await import('windows-foreground-love')).allowSetForegroundWindow(processId);
|
||||||
const waitMarkerFilePath = createWaitMarkerFile(args.verbose);
|
} catch (error) {
|
||||||
if (waitMarkerFilePath) {
|
logService.error(error);
|
||||||
addArg(process.argv, '--waitMarkerFilePath', waitMarkerFilePath);
|
}
|
||||||
args.waitMarkerFilePath = waitMarkerFilePath;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
startup(args);
|
|
||||||
|
private quit(accessor: ServicesAccessor, reason?: ExpectedError | Error): void {
|
||||||
|
const logService = accessor.get(ILogService);
|
||||||
|
const lifecycleService = accessor.get(ILifecycleService);
|
||||||
|
|
||||||
|
let exitCode = 0;
|
||||||
|
|
||||||
|
if (reason) {
|
||||||
|
if ((reason as ExpectedError).isExpected) {
|
||||||
|
if (reason.message) {
|
||||||
|
logService.trace(reason.message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
exitCode = 1; // signal error to the outside
|
||||||
|
|
||||||
|
if (reason.stack) {
|
||||||
|
logService.error(reason.stack);
|
||||||
|
} else {
|
||||||
|
logService.error(`Startup error: ${reason.toString()}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lifecycleService.kill(exitCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
main();
|
// Main Startup
|
||||||
|
const code = new CodeMain();
|
||||||
|
code.main();
|
Loading…
Reference in a new issue