Skip to content

Commit 819e63a

Browse files
browser: share activate() setup between different entrypoints (#4341)
## Problem We currently have `extension.ts#activate()` and `extensionWeb.ts#activate()` where the web version is basically a subset of the main `activate()`. This creates code duplication. ## Solution In `extensionShared.ts` have a shared activate function which both entrypoints will call. This function will consist of the same setup code regardless of entrypoint, this will de-duplicate the code. Note in activation order matters, so we may have to do some hacks if we run in to any new issues as we migrate shared code from `extension.ts` in to `extensionShared.ts`. <!--- REMINDER: - Read CONTRIBUTING.md first. - Add test coverage for your changes. - Update the changelog using `npm run newChange`. - Link to related issues/commits. - Testing: how did you test your changes? - Screenshots --> ## License By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. --------- Signed-off-by: nkomonen <[email protected]>
1 parent 0bf7771 commit 819e63a

File tree

3 files changed

+71
-111
lines changed

3 files changed

+71
-111
lines changed

src/extension.ts

Lines changed: 14 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -9,35 +9,27 @@ import * as nls from 'vscode-nls'
99
import * as codecatalyst from './codecatalyst/activation'
1010
import { activate as activateAwsExplorer } from './awsexplorer/activation'
1111
import { activate as activateCloudWatchLogs } from './cloudWatchLogs/activation'
12-
import { initialize as initializeCredentials } from './auth/activation'
13-
import { initializeAwsCredentialsStatusBarItem } from './auth/ui/statusBarItem'
14-
import { LoginManager } from './auth/deprecated/loginManager'
1512
import { CredentialsProviderManager } from './auth/providers/credentialsProviderManager'
1613
import { SharedCredentialsProviderFactory } from './auth/providers/sharedCredentialsProviderFactory'
1714
import { activate as activateSchemas } from './eventSchemas/activation'
1815
import { activate as activateLambda } from './lambda/activation'
19-
import { DefaultAWSClientBuilder } from './shared/awsClientBuilder'
2016
import { activate as activateCloudFormationTemplateRegistry } from './shared/cloudformation/activation'
2117
import { endpointsFileUrl } from './shared/constants'
22-
import { DefaultAwsContext } from './shared/awsContext'
2318
import { AwsContextCommands } from './shared/awsContextCommands'
2419
import {
2520
getIdeProperties,
2621
getToolkitEnvironmentDetails,
27-
initializeComputeRegion,
2822
isCloud9,
2923
isSageMaker,
3024
showWelcomeMessage,
3125
} from './shared/extensionUtilities'
3226
import { getLogger, Logger } from './shared/logger/logger'
33-
import { activate as activateLogger } from './shared/logger/activation'
3427
import { getEndpointsFromFetcher, RegionProvider } from './shared/regions/regionProvider'
3528
import { FileResourceFetcher } from './shared/resourcefetcher/fileResourceFetcher'
3629
import { HttpResourceFetcher } from './shared/resourcefetcher/httpResourceFetcher'
3730
import { activate as activateEcr } from './ecr/activation'
3831
import { activate as activateEc2 } from './ec2/activation'
3932
import { activate as activateSam } from './shared/sam/activation'
40-
import { activate as activateTelemetry } from './shared/telemetry/activation'
4133
import { activate as activateS3 } from './s3/activation'
4234
import * as awsFiletypes from './shared/awsFiletypes'
4335
import { activate as activateCodeWhisperer, shutdown as codewhispererShutdown } from './codewhisperer/activation'
@@ -52,7 +44,6 @@ import { activate as activateIot } from './iot/activation'
5244
import { activate as activateDev } from './dev/activation'
5345
import { activate as activateApplicationComposer } from './applicationcomposer/activation'
5446
import { activate as activateRedshift } from './redshift/activation'
55-
import { CredentialsStore } from './auth/credentials/store'
5647
import { activate as activateCWChat } from './amazonq/activation'
5748
import { activate as activateQGumby } from './amazonqGumby/activation'
5849
import { getSamCliContext } from './shared/sam/cli/samCliContext'
@@ -61,7 +52,7 @@ import { EnvVarsCredentialsProvider } from './auth/providers/envVarsCredentialsP
6152
import { EcsCredentialsProvider } from './auth/providers/ecsCredentialsProvider'
6253
import { SchemaService } from './shared/schemas'
6354
import { AwsResourceManager } from './dynamicResources/awsResourceManager'
64-
import globals, { initialize } from './shared/extensionGlobals'
55+
import globals from './shared/extensionGlobals'
6556
import { Experiments, Settings } from './shared/settings'
6657
import { isReleaseVersion } from './shared/vscode/env'
6758
import { Commands, registerErrorHandler as registerCommandErrorHandler } from './shared/vscode/commands2'
@@ -72,34 +63,24 @@ import { isUserCancelledError, resolveErrorMessageToDisplay, ToolkitError } from
7263
import { Logging } from './shared/logger/commands'
7364
import { showMessageWithUrl, showViewLogsMessage } from './shared/utilities/messages'
7465
import { registerWebviewErrorHandler } from './webviews/server'
75-
import { registerCommands, initializeManifestPaths } from './extensionShared'
7666
import { ChildProcess } from './shared/utilities/childProcess'
7767
import { initializeNetworkAgent } from './codewhisperer/client/agent'
7868
import { Timeout } from './shared/utilities/timeoutUtils'
7969
import { submitFeedback } from './feedback/vue/submitFeedback'
8070
import { showQuickStartWebview } from './shared/extensionStartup'
71+
import { activateShared } from './extensionShared'
8172

8273
let localize: nls.LocalizeFunc
8374

8475
export async function activate(context: vscode.ExtensionContext) {
85-
initializeNetworkAgent()
86-
await initializeComputeRegion()
8776
const activationStartedOn = Date.now()
8877
localize = nls.loadMessageBundle()
8978

90-
initialize(context)
9179
globals.machineId = await getMachineId()
92-
initializeManifestPaths(context)
9380

94-
const toolkitOutputChannel = vscode.window.createOutputChannel(
95-
localize('AWS.channel.aws.toolkit', '{0} Toolkit', getIdeProperties().company),
96-
{ log: true }
97-
)
98-
await activateLogger(context, toolkitOutputChannel)
9981
const remoteInvokeOutputChannel = vscode.window.createOutputChannel(
10082
localize('AWS.channel.aws.remoteInvoke', '{0} Remote Invocations', getIdeProperties().company)
10183
)
102-
globals.outputChannel = toolkitOutputChannel
10384

10485
registerCommandErrorHandler((info, error) => {
10586
const defaultMessage = localize('AWS.generic.message.error', 'Failed to run command: {0}', info.id)
@@ -124,15 +105,11 @@ export async function activate(context: vscode.ExtensionContext) {
124105
}
125106

126107
try {
127-
initializeCredentialsProviderManager()
128-
129-
const endpointsProvider = makeEndpointsProvider()
108+
// IMPORTANT: If you are doing setup that should also work in browser, it should be done in the function below
109+
await activateShared(context, () => RegionProvider.fromEndpointsProvider(makeEndpointsProvider()))
130110

131-
const awsContext = new DefaultAwsContext()
132-
globals.awsContext = awsContext
133-
const regionProvider = RegionProvider.fromEndpointsProvider(endpointsProvider)
134-
const credentialsStore = new CredentialsStore()
135-
const loginManager = new LoginManager(globals.awsContext, credentialsStore)
111+
initializeNetworkAgent()
112+
initializeCredentialsProviderManager()
136113

137114
const toolkitEnvDetails = getToolkitEnvironmentDetails()
138115
// Splits environment details by new line, filter removes the empty string
@@ -141,11 +118,7 @@ export async function activate(context: vscode.ExtensionContext) {
141118
.filter(Boolean)
142119
.forEach(line => getLogger().info(line))
143120

144-
await initializeAwsCredentialsStatusBarItem(awsContext, context)
145-
globals.regionProvider = regionProvider
146-
globals.loginManager = loginManager
147-
globals.awsContextCommands = new AwsContextCommands(regionProvider, Auth.instance)
148-
globals.sdkClientBuilder = new DefaultAWSClientBuilder(awsContext)
121+
globals.awsContextCommands = new AwsContextCommands(globals.regionProvider, Auth.instance)
149122
globals.schemaService = new SchemaService()
150123
globals.resourceManager = new AwsResourceManager(context)
151124
// Create this now, but don't call vscode.window.registerUriHandler() until after all
@@ -155,9 +128,6 @@ export async function activate(context: vscode.ExtensionContext) {
155128
const settings = Settings.instance
156129
const experiments = Experiments.instance
157130

158-
await activateTelemetry(context, awsContext, settings)
159-
await initializeCredentials(context, awsContext, loginManager)
160-
161131
experiments.onDidChange(({ key }) => {
162132
telemetry.aws_experimentActivation.run(span => {
163133
// Record the key prior to reading the setting as `get` may throw
@@ -173,12 +143,12 @@ export async function activate(context: vscode.ExtensionContext) {
173143
extensionContext: context,
174144
awsContext: globals.awsContext,
175145
samCliContext: getSamCliContext,
176-
regionProvider: regionProvider,
177-
outputChannel: toolkitOutputChannel,
146+
regionProvider: globals.regionProvider,
147+
outputChannel: globals.outputChannel,
178148
invokeOutputChannel: remoteInvokeOutputChannel,
179149
telemetryService: globals.telemetry,
180150
uriHandler: globals.uriHandler,
181-
credentialsStore,
151+
credentialsStore: globals.loginManager.store,
182152
}
183153

184154
try {
@@ -187,7 +157,6 @@ export async function activate(context: vscode.ExtensionContext) {
187157
getLogger().debug(`Developer Tools (internal): failed to activate: ${(error as Error).message}`)
188158
}
189159

190-
registerCommands(context)
191160
context.subscriptions.push(submitFeedback.register(context))
192161

193162
// do not enable codecatalyst for sagemaker
@@ -203,8 +172,8 @@ export async function activate(context: vscode.ExtensionContext) {
203172

204173
await activateAwsExplorer({
205174
context: extContext,
206-
regionProvider,
207-
toolkitOutputChannel,
175+
regionProvider: globals.regionProvider,
176+
toolkitOutputChannel: globals.outputChannel,
208177
remoteInvokeOutputChannel,
209178
})
210179

@@ -219,7 +188,7 @@ export async function activate(context: vscode.ExtensionContext) {
219188

220189
await activateLambda(extContext)
221190

222-
await activateSsmDocument(context, globals.awsContext, regionProvider, toolkitOutputChannel)
191+
await activateSsmDocument(context, globals.awsContext, globals.regionProvider, globals.outputChannel)
223192

224193
await activateSam(extContext)
225194

@@ -247,7 +216,7 @@ export async function activate(context: vscode.ExtensionContext) {
247216
await activateApplicationComposer(context)
248217
}
249218

250-
await activateStepFunctions(context, awsContext, toolkitOutputChannel)
219+
await activateStepFunctions(context, globals.awsContext, globals.outputChannel)
251220

252221
await activateRedshift(extContext)
253222

src/extensionShared.ts

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,63 @@
99
*/
1010

1111
import vscode from 'vscode'
12-
import globals from './shared/extensionGlobals'
12+
import globals, { initialize } from './shared/extensionGlobals'
1313
import { join } from 'path'
1414
import { Commands } from './shared/vscode/commands2'
1515
import { documentationUrl, githubCreateIssueUrl, githubUrl } from './shared/constants'
1616
import { getIdeProperties, aboutToolkit } from './shared/extensionUtilities'
1717
import { telemetry } from './shared/telemetry/telemetry'
1818
import { openUrl } from './shared/utilities/vsCodeUtils'
1919

20-
export function initializeManifestPaths(extensionContext: vscode.ExtensionContext) {
21-
globals.manifestPaths.endpoints = extensionContext.asAbsolutePath(join('resources', 'endpoints.json'))
22-
globals.manifestPaths.lambdaSampleRequests = extensionContext.asAbsolutePath(
20+
import { activate as activateLogger } from './shared/logger/activation'
21+
import { initializeComputeRegion } from './shared/extensionUtilities'
22+
import { activate as activateTelemetry } from './shared/telemetry/activation'
23+
import { DefaultAwsContext } from './shared/awsContext'
24+
import { Settings } from './shared/settings'
25+
import { DefaultAWSClientBuilder } from './shared/awsClientBuilder'
26+
import { initialize as initializeAuth } from './auth/activation'
27+
import { LoginManager } from './auth/deprecated/loginManager'
28+
import { CredentialsStore } from './auth/credentials/store'
29+
import { initializeAwsCredentialsStatusBarItem } from './auth/ui/statusBarItem'
30+
import { RegionProvider } from './shared/regions/regionProvider'
31+
32+
/**
33+
* Activation/setup code that is shared by the regular (nodejs) extension AND browser-compatible extension.
34+
* Most setup code should live here, unless there is a reason not to.
35+
*
36+
* @param getRegionProvider - HACK telemetry requires the region provider but we cannot create it yet in this
37+
* "shared" function since it breaks in browser. So for now the caller must provide it.
38+
*/
39+
export async function activateShared(context: vscode.ExtensionContext, getRegionProvider: () => RegionProvider) {
40+
// Setup the logger
41+
const toolkitOutputChannel = vscode.window.createOutputChannel('AWS Toolkit', { log: true })
42+
await activateLogger(context, toolkitOutputChannel)
43+
globals.outputChannel = toolkitOutputChannel
44+
45+
//setup globals
46+
globals.awsContext = new DefaultAwsContext()
47+
globals.sdkClientBuilder = new DefaultAWSClientBuilder(globals.awsContext)
48+
globals.loginManager = new LoginManager(globals.awsContext, new CredentialsStore())
49+
50+
// some "initialize" functions
51+
await initializeComputeRegion()
52+
initialize(context)
53+
54+
// order matters here
55+
globals.manifestPaths.endpoints = context.asAbsolutePath(join('resources', 'endpoints.json'))
56+
globals.manifestPaths.lambdaSampleRequests = context.asAbsolutePath(
2357
join('resources', 'vs-lambda-sample-request-manifest.xml')
2458
)
59+
globals.regionProvider = getRegionProvider()
60+
61+
// telemetry
62+
await activateTelemetry(context, globals.awsContext, Settings.instance)
63+
64+
// auth
65+
await initializeAuth(context, globals.awsContext, globals.loginManager)
66+
await initializeAwsCredentialsStatusBarItem(globals.awsContext, context)
67+
68+
registerCommands(context)
2569
}
2670

2771
/**

src/extensionWeb.ts

Lines changed: 9 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,9 @@
55

66
import * as vscode from 'vscode'
77
import { setInBrowser } from './common/browserUtils'
8-
import { activate as activateLogger } from './shared/logger/activation'
9-
import { initializeComputeRegion } from './shared/extensionUtilities'
10-
import { activate as activateTelemetry } from './shared/telemetry/activation'
118
import { getLogger } from './shared/logger'
12-
import { DefaultAwsContext } from './shared/awsContext'
13-
import { Settings } from './shared/settings'
14-
import globals, { initialize } from './shared/extensionGlobals'
15-
import { registerCommands, initializeManifestPaths } from './extensionShared'
9+
import { activateShared } from './extensionShared'
1610
import { RegionProvider, defaultRegion } from './shared/regions/regionProvider'
17-
import { DefaultAWSClientBuilder } from './shared/awsClientBuilder'
18-
import { initialize as initializeCredentials } from './auth/activation'
19-
import { LoginManager } from './auth/deprecated/loginManager'
20-
import { CredentialsStore } from './auth/credentials/store'
21-
import { initializeAwsCredentialsStatusBarItem } from './auth/ui/statusBarItem'
2211

2312
export async function activate(context: vscode.ExtensionContext) {
2413
setInBrowser(true) // THIS MUST ALWAYS BE FIRST
@@ -28,63 +17,21 @@ export async function activate(context: vscode.ExtensionContext) {
2817
)
2918

3019
try {
31-
// Setup the logger
32-
const toolkitOutputChannel = vscode.window.createOutputChannel('AWS Toolkit', { log: true })
33-
await activateLogger(context, toolkitOutputChannel)
34-
35-
setupGlobals()
36-
37-
await initializeComputeRegion()
38-
initialize(context)
39-
initializeManifestPaths(context)
40-
41-
await activateTelemetry(context, globals.awsContext, Settings.instance)
42-
43-
await initializeCredentials(context, globals.awsContext, globals.loginManager)
44-
await initializeAwsCredentialsStatusBarItem(globals.awsContext, context)
45-
46-
registerCommands(context)
20+
// IMPORTANT: Any new activation code should be done in the function below unless
21+
// it is browser specific activation code.
22+
await activateShared(context, () => {
23+
return {
24+
guessDefaultRegion: () => defaultRegion,
25+
} as RegionProvider
26+
})
4727
} catch (error) {
4828
const stacktrace = (error as Error).stack?.split('\n')
4929
// truncate if the stacktrace is unusually long
5030
if (stacktrace !== undefined && stacktrace.length > 40) {
5131
stacktrace.length = 40
5232
}
53-
getLogger().error('Failed to activate extension in Browser', error)
54-
throw error
33+
getLogger().error(`Failed to activate extension`, error)
5534
}
5635
}
5736

58-
/** Set up values for the `globals` object */
59-
function setupGlobals() {
60-
globals.awsContext = new DefaultAwsContext()
61-
globals.sdkClientBuilder = new DefaultAWSClientBuilder(globals.awsContext)
62-
63-
globals.loginManager = new LoginManager(globals.awsContext, new CredentialsStore())
64-
65-
setupGlobalsTempStubs()
66-
}
67-
68-
/**
69-
* Since we are still incrementally enabling certain functionality
70-
* in the browser, certain global variables will not have been set
71-
* and functionality we enabled will not work.
72-
*
73-
* This function sets up the minimum-required stubs for the necessary
74-
* variables to get things working.
75-
*
76-
* If needed we can eventually create the real implementations instead
77-
* of stubbing.
78-
*/
79-
function setupGlobalsTempStubs() {
80-
// This is required for telemetry to run.
81-
// The default region is arbitrary for now.
82-
// We didn't create an actual instance since it
83-
// will require non-trivial work to get the creation
84-
// of the instance in the browser working.
85-
globals.regionProvider = {
86-
guessDefaultRegion: () => defaultRegion,
87-
} as RegionProvider
88-
}
89-
9037
export async function deactivate() {}

0 commit comments

Comments
 (0)