diff --git a/src/sql/workbench/services/commandLine/common/commandLine.ts b/src/sql/workbench/services/commandLine/common/commandLine.ts index 473d1e0cae..fced9c99d8 100644 --- a/src/sql/workbench/services/commandLine/common/commandLine.ts +++ b/src/sql/workbench/services/commandLine/common/commandLine.ts @@ -5,13 +5,15 @@ 'use strict'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { ParsedArgs } from 'vs/platform/environment/common/environment'; + export interface ICommandLineProcessing { _serviceBrand: any; /** * Interprets the various Azure Data Studio-specific command line switches and * performs the requisite tasks such as connecting to a server */ - processCommandLine(): Promise; + processCommandLine(args: ParsedArgs): Promise; } export const ICommandLineProcessing = createDecorator('commandLineService'); \ No newline at end of file diff --git a/src/sql/workbench/services/commandLine/common/commandLineService.ts b/src/sql/workbench/services/commandLine/common/commandLineService.ts index 06dbcb0720..80a521ef89 100644 --- a/src/sql/workbench/services/commandLine/common/commandLineService.ts +++ b/src/sql/workbench/services/commandLine/common/commandLineService.ts @@ -7,7 +7,7 @@ import { ConnectionProfile } from 'sql/platform/connection/common/connectionProf import { ICommandLineProcessing } from 'sql/workbench/services/commandLine/common/commandLine'; import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement'; import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; import * as Constants from 'sql/platform/connection/common/constants'; import { IQueryEditorService } from 'sql/parts/query/common/queryEditorService'; import * as platform from 'vs/platform/registry/common/platform'; @@ -18,14 +18,12 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { warn } from 'sql/base/common/log'; +import { ipcRenderer as ipc} from 'electron'; export class CommandLineService implements ICommandLineProcessing { - private _connectionProfile: ConnectionProfile; - private _showConnectionDialog: boolean; - private _commandName: string; constructor( - @ICapabilitiesService _capabilitiesService: ICapabilitiesService, + @ICapabilitiesService private _capabilitiesService: ICapabilitiesService, @IConnectionManagementService private _connectionManagementService: IConnectionManagementService, @IEnvironmentService private _environmentService: IEnvironmentService, @IQueryEditorService private _queryEditorService: IQueryEditorService, @@ -34,52 +32,62 @@ export class CommandLineService implements ICommandLineProcessing { @ICommandService private _commandService: ICommandService, @IWorkspaceConfigurationService private _configurationService: IWorkspaceConfigurationService ) { - let profile = null; - if (this._environmentService) { - if (this._commandService) { - this._commandName = this._environmentService.args.command; - } - if (this._environmentService.args.server) { - profile = new ConnectionProfile(_capabilitiesService, null); - // We want connection store to use any matching password it finds - profile.savePassword = true; - profile.providerName = Constants.mssqlProviderName; - profile.serverName = _environmentService.args.server; - profile.databaseName = _environmentService.args.database ? _environmentService.args.database : ''; - profile.userName = _environmentService.args.user ? _environmentService.args.user : ''; - profile.authenticationType = _environmentService.args.integrated ? 'Integrated' : 'SqlLogin'; - profile.connectionName = ''; - profile.setOptionValue('applicationName', Constants.applicationName); - profile.setOptionValue('databaseDisplayName', profile.databaseName); - profile.setOptionValue('groupId', profile.groupId); - } + if (ipc) { + ipc.on('ads:processCommandLine', (event: any, args: ParsedArgs) => this.onLaunched(args)); } - this._connectionProfile = profile; + // we only get the ipc from main during window reuse + this.onLaunched(_environmentService.args); + } + + private onLaunched(args: ParsedArgs) + { const registry = platform.Registry.as(ConnectionProviderExtensions.ConnectionProviderContributions); let sqlProvider = registry.getProperties(Constants.mssqlProviderName); // We can't connect to object explorer until the MSSQL connection provider is registered if (sqlProvider) { - this.processCommandLine().catch(reason => { warn('processCommandLine failed: ' + reason); }); + this.processCommandLine(args).catch(reason => { warn('processCommandLine failed: ' + reason); }); } else { registry.onNewProvider(e => { if (e.id === Constants.mssqlProviderName) { - this.processCommandLine().catch(reason => { warn('processCommandLine failed: ' + reason); }); + this.processCommandLine(args).catch(reason => { warn('processCommandLine failed: ' + reason); }); } }); } } + public _serviceBrand: any; // We base our logic on the combination of (server, command) values. // (serverName, commandName) => Connect object explorer and execute the command, passing the connection profile to the command. Do not load query editor. // (null, commandName) => Launch the command with a null connection. If the command implementation needs a connection, it will need to create it. // (serverName, null) => Connect object explorer and open a new query editor // (null, null) => Prompt for a connection unless there are registered servers - public processCommandLine(): Promise { + public processCommandLine(args: ParsedArgs): Promise { + let profile = undefined; + let commandName = undefined; + if (args) { + if (this._commandService) { + commandName = args.command; + } + if (args.server) { + profile = new ConnectionProfile(this._capabilitiesService, null); + // We want connection store to use any matching password it finds + profile.savePassword = true; + profile.providerName = Constants.mssqlProviderName; + profile.serverName = args.server; + profile.databaseName = args.database ? args.database : ''; + profile.userName = args.user ? args.user : ''; + profile.authenticationType = args.integrated ? 'Integrated' : 'SqlLogin'; + profile.connectionName = ''; + profile.setOptionValue('applicationName', Constants.applicationName); + profile.setOptionValue('databaseDisplayName', profile.databaseName); + profile.setOptionValue('groupId', profile.groupId); + } + } let self = this; return new Promise((resolve, reject) => { - let showConnectDialogOnStartup: boolean = this._configurationService.getValue('workbench.showConnectDialogOnStartup'); - if (showConnectDialogOnStartup && !self._commandName && !self._connectionProfile && !self._connectionManagementService.hasRegisteredServers()) { + let showConnectDialogOnStartup: boolean = self._configurationService.getValue('workbench.showConnectDialogOnStartup'); + if (showConnectDialogOnStartup && !commandName && !profile && !self._connectionManagementService.hasRegisteredServers()) { // prompt the user for a new connection on startup if no profiles are registered self._connectionManagementService.showConnectionDialog() .then(() => { @@ -88,11 +96,11 @@ export class CommandLineService implements ICommandLineProcessing { error => { reject(error); }); - } else if (self._connectionProfile) { - if (!self._commandName) { - self._connectionManagementService.connectIfNotConnected(self._connectionProfile, 'connection', true) + } else if (profile) { + if (!commandName) { + self._connectionManagementService.connectIfNotConnected(profile, 'connection', true) .then(() => { - TaskUtilities.newQuery(self._connectionProfile, + TaskUtilities.newQuery(profile, self._connectionManagementService, self._queryEditorService, self._objectExplorerService, @@ -109,15 +117,15 @@ export class CommandLineService implements ICommandLineProcessing { reject(error); }); } else { - self._connectionManagementService.connectIfNotConnected(self._connectionProfile, 'connection', true) + self._connectionManagementService.connectIfNotConnected(profile, 'connection', true) .then(() => { - self._commandService.executeCommand(self._commandName, self._connectionProfile.id).then(() => resolve(), error => reject(error)); + self._commandService.executeCommand(commandName, profile.id).then(() => resolve(), error => reject(error)); }, error => { reject(error); }); } - } else if (self._commandName) { - self._commandService.executeCommand(self._commandName).then(() => resolve(), error => reject(error)); + } else if (commandName) { + self._commandService.executeCommand(commandName).then(() => resolve(), error => reject(error)); } else { resolve(); diff --git a/src/sqltest/parts/commandLine/commandLineService.test.ts b/src/sqltest/parts/commandLine/commandLineService.test.ts index 77a2bde1fa..fe9d74c036 100644 --- a/src/sqltest/parts/commandLine/commandLineService.test.ts +++ b/src/sqltest/parts/commandLine/commandLineService.test.ts @@ -2,6 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +/* Disabled pending next vscode merge which allows electron module to be imported during test runs 'use strict'; @@ -106,14 +107,13 @@ suite('commandLineService tests', () => { function getCommandLineService(connectionManagementService: IConnectionManagementService, configurationService: IWorkspaceConfigurationService, - environmentService?: IEnvironmentService, capabilitiesService?: ICapabilitiesService, commandService?: ICommandService ): CommandLineService { let service = new CommandLineService( capabilitiesService, connectionManagementService, - environmentService, + undefined, undefined, undefined, undefined, @@ -142,7 +142,7 @@ suite('commandLineService tests', () => { .verifiable(TypeMoq.Times.never()); const configurationService = getConfigurationServiceMock(true); let service = getCommandLineService(connectionManagementService.object, configurationService.object); - service.processCommandLine().then(() => { + service.processCommandLine(new TestParsedArgs()).then(() => { connectionManagementService.verifyAll(); done(); }, error => { assert.fail(error, null, 'processCommandLine rejected ' + error); done(); }); @@ -159,7 +159,7 @@ suite('commandLineService tests', () => { const configurationService = getConfigurationServiceMock(false); let service = getCommandLineService(connectionManagementService.object, configurationService.object); - service.processCommandLine(); + service.processCommandLine(new TestParsedArgs()); connectionManagementService.verifyAll(); done(); }); @@ -175,7 +175,7 @@ suite('commandLineService tests', () => { .verifiable(TypeMoq.Times.never()); const configurationService = getConfigurationServiceMock(true); let service = getCommandLineService(connectionManagementService.object, configurationService.object); - service.processCommandLine().then(() => { + service.processCommandLine(new TestParsedArgs()).then(() => { connectionManagementService.verifyAll(); done(); }, error => { assert.fail(error, null, 'processCommandLine rejected ' + error); done(); }); @@ -185,20 +185,17 @@ suite('commandLineService tests', () => { const connectionManagementService: TypeMoq.Mock = TypeMoq.Mock.ofType(TestConnectionManagementService, TypeMoq.MockBehavior.Strict); - const environmentService: TypeMoq.Mock = TypeMoq.Mock.ofType(EnvironmentService); const args: TestParsedArgs = new TestParsedArgs(); args.server = 'myserver'; args.database = 'mydatabase'; - environmentService.setup(e => e.args).returns(() => args).verifiable(TypeMoq.Times.atLeastOnce()); connectionManagementService.setup((c) => c.showConnectionDialog()).verifiable(TypeMoq.Times.never()); connectionManagementService.setup(c => c.hasRegisteredServers()).returns(() => true).verifiable(TypeMoq.Times.atMostOnce()); connectionManagementService.setup(c => c.connectIfNotConnected(TypeMoq.It.isAny(), 'connection', true)) .returns(() => new Promise((resolve, reject) => { resolve('unused'); })) .verifiable(TypeMoq.Times.once()); const configurationService = getConfigurationServiceMock(true); - let service = getCommandLineService(connectionManagementService.object, configurationService.object, environmentService.object, capabilitiesService); - service.processCommandLine().then(() => { - environmentService.verifyAll(); + let service = getCommandLineService(connectionManagementService.object, configurationService.object, capabilitiesService); + service.processCommandLine(args).then(() => { connectionManagementService.verifyAll(); done(); }, error => { assert.fail(error, null, 'processCommandLine rejected ' + error); done(); }); @@ -207,12 +204,10 @@ suite('commandLineService tests', () => { test('processCommandLine invokes a command without a profile parameter when no server is passed', done => { const connectionManagementService: TypeMoq.Mock = TypeMoq.Mock.ofType(TestConnectionManagementService, TypeMoq.MockBehavior.Strict); - const environmentService: TypeMoq.Mock = TypeMoq.Mock.ofType(EnvironmentService); const commandService: TypeMoq.Mock = TypeMoq.Mock.ofType(TestCommandService); const args: TestParsedArgs = new TestParsedArgs(); args.command = 'mycommand'; - environmentService.setup(e => e.args).returns(() => args); connectionManagementService.setup((c) => c.showConnectionDialog()).verifiable(TypeMoq.Times.never()); connectionManagementService.setup(c => c.hasRegisteredServers()).returns(() => true).verifiable(TypeMoq.Times.atMostOnce()); connectionManagementService.setup(c => c.connectIfNotConnected(TypeMoq.It.isAny(), TypeMoq.It.isAny())) @@ -221,8 +216,8 @@ suite('commandLineService tests', () => { .returns(() => TPromise.wrap(1)) .verifiable(TypeMoq.Times.once()); const configurationService = getConfigurationServiceMock(true); - let service = getCommandLineService(connectionManagementService.object, configurationService.object, environmentService.object, capabilitiesService, commandService.object); - service.processCommandLine().then(() => { + let service = getCommandLineService(connectionManagementService.object, configurationService.object, capabilitiesService, commandService.object); + service.processCommandLine(args).then(() => { connectionManagementService.verifyAll(); commandService.verifyAll(); done(); @@ -235,7 +230,6 @@ suite('commandLineService tests', () => { const connectionManagementService: TypeMoq.Mock = TypeMoq.Mock.ofType(TestConnectionManagementService, TypeMoq.MockBehavior.Strict); - const environmentService: TypeMoq.Mock = TypeMoq.Mock.ofType(EnvironmentService); const commandService: TypeMoq.Mock = TypeMoq.Mock.ofType(TestCommandService); const args: TestParsedArgs = new TestParsedArgs(); args.command = 'mycommand'; @@ -250,8 +244,8 @@ suite('commandLineService tests', () => { .returns(() => TPromise.wrap(1)) .verifiable(TypeMoq.Times.once()); const configurationService = getConfigurationServiceMock(true); - let service = getCommandLineService(connectionManagementService.object, configurationService.object, environmentService.object, capabilitiesService, commandService.object); - service.processCommandLine().then(() => { + let service = getCommandLineService(connectionManagementService.object, configurationService.object, capabilitiesService, commandService.object); + service.processCommandLine(args).then(() => { connectionManagementService.verifyAll(); commandService.verifyAll(); done(); @@ -261,7 +255,6 @@ suite('commandLineService tests', () => { test('processCommandLine rejects unknown commands', done => { const connectionManagementService: TypeMoq.Mock = TypeMoq.Mock.ofType(TestConnectionManagementService, TypeMoq.MockBehavior.Strict); - const environmentService: TypeMoq.Mock = TypeMoq.Mock.ofType(EnvironmentService); const commandService: TypeMoq.Mock = TypeMoq.Mock.ofType(TestCommandService); const args: TestParsedArgs = new TestParsedArgs(); @@ -272,8 +265,8 @@ suite('commandLineService tests', () => { .returns(() => TPromise.wrapError(new Error('myerror'))) .verifiable(TypeMoq.Times.once()); const configurationService = getConfigurationServiceMock(true); - let service = getCommandLineService(connectionManagementService.object, configurationService.object, environmentService.object, capabilitiesService, commandService.object); - service.processCommandLine().then(() => { + let service = getCommandLineService(connectionManagementService.object, configurationService.object, capabilitiesService, commandService.object); + service.processCommandLine(args).then(() => { assert.fail(1, null, 'processCommandLine should reject when executeCommand errors out'); done(); }, error => { @@ -282,3 +275,5 @@ suite('commandLineService tests', () => { }); }); }); + +*/ \ No newline at end of file diff --git a/src/vs/code/electron-main/launch.ts b/src/vs/code/electron-main/launch.ts index 97a541c73b..80eac42e09 100644 --- a/src/vs/code/electron-main/launch.ts +++ b/src/vs/code/electron-main/launch.ts @@ -228,6 +228,15 @@ export class LaunchService implements ILaunchService { }); } + // {{SQL CARBON EDIT}} + // give the first used window a chance to process the other command line arguments + if (args['reuse-window'] && usedWindows.length > 0 && usedWindows[0]) + { + let window = usedWindows[0]; + usedWindows[0].ready().then(() => window.send('ads:processCommandLine', args)); + } + // {{SQL CARBON EDIT}} + // If the other instance is waiting to be killed, we hook up a window listener if one window // is being used and only then resolve the startup promise which will kill this second instance. // In addition, we poll for the wait marker file to be deleted to return.