Skip to content

Commit 75330d3

Browse files
committed
[jb] experimental support of warm up in prebuilds
1 parent f5b8dd3 commit 75330d3

File tree

7 files changed

+196
-6
lines changed

7 files changed

+196
-6
lines changed

components/gitpod-protocol/data/gitpod-schema.json

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,22 @@
271271
"items": {
272272
"type": "string"
273273
}
274+
},
275+
"prebuilds": {
276+
"type": "object",
277+
"description": "Enable warming up of IntelliJ in prebuilds.",
278+
"additionalProperties": false,
279+
"properties": {
280+
"version": {
281+
"type": "string",
282+
"enum": [
283+
"stable",
284+
"latest",
285+
"both"
286+
],
287+
"description": "Whether only stable, latest or both versions should be warmed up. Default is stable only."
288+
}
289+
}
274290
}
275291
}
276292
},
@@ -285,6 +301,22 @@
285301
"items": {
286302
"type": "string"
287303
}
304+
},
305+
"prebuilds": {
306+
"type": "object",
307+
"description": "Enable warming up of GoLand in prebuilds.",
308+
"additionalProperties": false,
309+
"properties": {
310+
"version": {
311+
"type": "string",
312+
"enum": [
313+
"stable",
314+
"latest",
315+
"both"
316+
],
317+
"description": "Whether only stable, latest or both versions should be warmed up. Default is stable only."
318+
}
319+
}
288320
}
289321
}
290322
},
@@ -299,6 +331,22 @@
299331
"items": {
300332
"type": "string"
301333
}
334+
},
335+
"prebuilds": {
336+
"type": "object",
337+
"description": "Enable warming up of PyCharm in prebuilds.",
338+
"additionalProperties": false,
339+
"properties": {
340+
"version": {
341+
"type": "string",
342+
"enum": [
343+
"stable",
344+
"latest",
345+
"both"
346+
],
347+
"description": "Whether only stable, latest or both versions should be warmed up. Default is stable only."
348+
}
349+
}
302350
}
303351
}
304352
},
@@ -313,6 +361,22 @@
313361
"items": {
314362
"type": "string"
315363
}
364+
},
365+
"prebuilds": {
366+
"type": "object",
367+
"description": "Enable warming up of PhpStorm in prebuilds.",
368+
"additionalProperties": false,
369+
"properties": {
370+
"version": {
371+
"type": "string",
372+
"enum": [
373+
"stable",
374+
"latest",
375+
"both"
376+
],
377+
"description": "Whether only stable, latest or both versions should be warmed up. Default is stable only."
378+
}
379+
}
316380
}
317381
}
318382
}

components/gitpod-protocol/go/gitpod-config-types.go

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/gitpod-protocol/src/protocol.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,19 @@ export interface VSCodeConfig {
539539
extensions?: string[];
540540
}
541541

542+
export interface JetBrainsConfig {
543+
intellij?: JetBrainsProductConfig;
544+
goland?: JetBrainsProductConfig;
545+
pycharm?: JetBrainsProductConfig;
546+
phpstorm?: JetBrainsProductConfig;
547+
}
548+
export interface JetBrainsProductConfig {
549+
prebuilds?: JetBrainsPrebuilds;
550+
}
551+
export interface JetBrainsPrebuilds {
552+
version?: "stable" | "latest" | "both";
553+
}
554+
542555
export interface RepositoryCloneInformation {
543556
url: string;
544557
checkoutLocation?: string;
@@ -555,6 +568,7 @@ export interface WorkspaceConfig {
555568
gitConfig?: { [config: string]: string };
556569
github?: GithubAppConfig;
557570
vscode?: VSCodeConfig;
571+
jetbrains?: JetBrainsConfig;
558572

559573
/** deprecated. Enabled by default **/
560574
experimentalNetwork?: boolean;

components/gitpod-protocol/src/workspace-instance.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ export interface WorkspaceInstanceRepoStatus {
207207
// ConfigurationIdeConfig ide config of WorkspaceInstanceConfiguration
208208
export interface ConfigurationIdeConfig {
209209
useLatest?: boolean;
210+
desktopIdeAlias?: string;
210211
}
211212

212213
// WorkspaceInstanceConfiguration contains all per-instance configuration

components/server/src/container-module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,12 @@ import { LocalMessageBroker, LocalRabbitMQBackedMessageBroker } from "./messagin
9797
import { contentServiceBinder } from "@gitpod/content-service/lib/sugar";
9898
import { ReferrerPrefixParser } from "./workspace/referrer-prefix-context-parser";
9999
import { InstallationAdminTelemetryDataProvider } from "./installation-admin/telemetry-data-provider";
100+
import { IDEService } from "./ide-service";
100101

101102
export const productionContainerModule = new ContainerModule((bind, unbind, isBound, rebind) => {
102103
bind(Config).toConstantValue(ConfigFile.fromFile());
103104
bind(IDEConfigService).toSelf().inSingletonScope();
105+
bind(IDEService).toSelf().inSingletonScope();
104106

105107
bind(UserService).toSelf().inSingletonScope();
106108
bind(UserDeletionService).toSelf().inSingletonScope();

components/server/src/ide-service.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/**
2+
* Copyright (c) 2022 Gitpod GmbH. All rights reserved.
3+
* Licensed under the GNU Affero General Public License (AGPL).
4+
* See License-AGPL.txt in the project root for license information.
5+
*/
6+
7+
import { JetBrainsConfig, TaskConfig, Workspace, WorkspaceInstance } from "@gitpod/gitpod-protocol";
8+
import { injectable } from "inversify";
9+
10+
@injectable()
11+
export class IDEService {
12+
resolveGitpodTasks(ws: Workspace, instance: WorkspaceInstance): TaskConfig[] {
13+
const tasks: TaskConfig[] = [];
14+
if (ws.config.tasks) {
15+
tasks.push(...ws.config.tasks);
16+
}
17+
const desktopIdeAlias = instance.configuration?.ideConfig?.desktopIdeAlias;
18+
// TODO(ak) layer JB products on prebuild workspaces and move logic to corresponding images
19+
if (
20+
ws.type === "prebuild" &&
21+
ws.config.jetbrains &&
22+
desktopIdeAlias &&
23+
desktopIdeAlias in ws.config.jetbrains
24+
) {
25+
const alias = desktopIdeAlias as keyof JetBrainsConfig;
26+
const prebuilds = ws.config.jetbrains[alias]?.prebuilds;
27+
let productCode;
28+
if (alias === "intellij") {
29+
productCode = "IIU";
30+
} else if (alias === "goland") {
31+
productCode = "GO";
32+
} else if (alias === "pycharm") {
33+
productCode = "PCP";
34+
} else if (alias === "phpstorm") {
35+
productCode = "PS";
36+
}
37+
if (prebuilds) {
38+
const warmUpStable =
39+
prebuilds.version === "latest"
40+
? ""
41+
: `
42+
# index stable release
43+
JB_BACKEND_DOWNLOAD_URL="https://download.jetbrains.com/product?type=release&distribution=linux&code=${productCode}"
44+
echo "$JB_BACKEND_DOWNLOAD_URL"
45+
46+
# download JB backend
47+
mkdir /tmp/backend && cd /tmp/backend || exit 1
48+
curl -sSLo backend.tar.gz "$JB_BACKEND_DOWNLOAD_URL" && tar -xf backend.tar.gz --strip-components=1 && rm backend.tar.gz
49+
50+
# config JB system config and caches aligned with runtime
51+
printf '\nshared.indexes.download.auto.consent=true' >> "/tmp/backend/bin/idea.properties"
52+
unset JAVA_TOOL_OPTIONS
53+
export IJ_HOST_CONFIG_BASE_DIR=/workspace/.config/JetBrains
54+
export IJ_HOST_SYSTEM_BASE_DIR=/workspace/.cache/JetBrains
55+
56+
# start JB backend in indexing mode
57+
/tmp/backend/bin/remote-dev-server.sh warmup "$GITPOD_REPO_ROOT"
58+
`;
59+
const warmUpLatest =
60+
prebuilds.version === "stable"
61+
? ""
62+
: `
63+
# index latest release
64+
JB_BACKEND_DOWNLOAD_URL="https://download.jetbrains.com/product?type=release,eap,rc&distribution=linux&code=${productCode}"
65+
echo "$JB_BACKEND_DOWNLOAD_URL"
66+
67+
# download JB backend
68+
mkdir /tmp/backend-latest && cd /tmp/backend-latest || exit 1
69+
curl -sSLo backend-latest.tar.gz "$JB_BACKEND_DOWNLOAD_URL" && tar -xf backend-latest.tar.gz --strip-components=1 && rm backend-latest.tar.gz
70+
71+
# config JB system config and caches aligned with runtime
72+
printf '\nshared.indexes.download.auto.consent=true' >> "/tmp/backend-latest/bin/idea.properties"
73+
unset JAVA_TOOL_OPTIONS
74+
export IJ_HOST_CONFIG_BASE_DIR=/workspace/.config/JetBrains-latest
75+
export IJ_HOST_SYSTEM_BASE_DIR=/workspace/.cache/JetBrains-latest
76+
77+
# start JB backend in indexing mode
78+
/tmp/backend-latest/bin/remote-dev-server.sh warmup "$GITPOD_REPO_ROOT"
79+
`;
80+
tasks.push({
81+
init: `| ${warmUpStable} ${warmUpLatest}`,
82+
});
83+
}
84+
}
85+
return tasks;
86+
}
87+
}

components/server/src/workspace/workspace-starter.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ import { Deferred } from "@gitpod/gitpod-protocol/lib/util/deferred";
109109
import { ExtendedUser } from "@gitpod/ws-manager/lib/constraints";
110110
import { increaseFailedInstanceStartCounter, increaseSuccessfulInstanceStartCounter } from "../prometheus-metrics";
111111
import { ContextParser } from "./context-parser-service";
112+
import { IDEService } from "../ide-service";
112113

113114
export interface StartWorkspaceOptions {
114115
rethrow?: boolean;
@@ -119,6 +120,7 @@ export interface StartWorkspaceOptions {
119120
const MAX_INSTANCE_START_RETRIES = 2;
120121
const INSTANCE_START_RETRY_INTERVAL_SECONDS = 2;
121122

123+
// TODO(ak) move to IDE service
122124
export const migrationIDESettings = (user: User) => {
123125
if (!user?.additionalData?.ideSettings || user.additionalData.ideSettings.settingVersion === "2.0") {
124126
return;
@@ -145,6 +147,7 @@ export const migrationIDESettings = (user: User) => {
145147
return newIDESettings;
146148
};
147149

150+
// TODO(ak) move to IDE service
148151
export const chooseIDE = (
149152
ideChoice: string,
150153
ideOptions: IDEOptions,
@@ -153,15 +156,17 @@ export const chooseIDE = (
153156
) => {
154157
const defaultIDEOption = ideOptions.options[ideOptions.defaultIde];
155158
const defaultIdeImage = useLatest ? defaultIDEOption.latestImage ?? defaultIDEOption.image : defaultIDEOption.image;
156-
const data: { desktopIdeImage?: string; ideImage: string } = {
159+
const data: { desktopIdeImage?: string; desktopIdeAlias?: string; ideImage: string } = {
157160
ideImage: defaultIdeImage,
158161
};
159162
const chooseOption = ideOptions.options[ideChoice];
160163
const isDesktopIde = chooseOption.type === "desktop";
161164
if (isDesktopIde) {
162165
data.desktopIdeImage = useLatest ? chooseOption?.latestImage ?? chooseOption?.image : chooseOption?.image;
163-
if (hasIdeSettingPerm) {
164-
data.desktopIdeImage = data.desktopIdeImage || ideChoice;
166+
if (data.desktopIdeImage) {
167+
data.desktopIdeAlias = ideChoice;
168+
} else if (hasIdeSettingPerm) {
169+
data.desktopIdeImage = ideChoice;
165170
}
166171
} else {
167172
data.ideImage = useLatest ? chooseOption?.latestImage ?? chooseOption?.image : chooseOption?.image;
@@ -181,6 +186,7 @@ export class WorkspaceStarter {
181186
@inject(WorkspaceManagerClientProvider) protected readonly clientProvider: WorkspaceManagerClientProvider;
182187
@inject(Config) protected readonly config: Config;
183188
@inject(IDEConfigService) private readonly ideConfigService: IDEConfigService;
189+
@inject(IDEService) private readonly ideService: IDEService;
184190
@inject(TracedWorkspaceDB) protected readonly workspaceDb: DBWithTracing<WorkspaceDB>;
185191
@inject(TracedUserDB) protected readonly userDB: DBWithTracing<UserDB>;
186192
@inject(TokenProvider) protected readonly tokenProvider: TokenProvider;
@@ -598,6 +604,7 @@ export class WorkspaceStarter {
598604
excludeFeatureFlags: NamedWorkspaceFeatureFlag[],
599605
ideConfig: IDEConfig,
600606
): Promise<WorkspaceInstance> {
607+
//#endregion IDE resolution TODO(ak) move to IDE service
601608
// TODO: Compatible with ide-config not deployed, need revert after ide-config deployed
602609
delete ideConfig.ideOptions.options["code-latest"];
603610
delete ideConfig.ideOptions.options["code-desktop-insiders"];
@@ -631,13 +638,15 @@ export class WorkspaceStarter {
631638
);
632639
configuration.ideImage = choose.ideImage;
633640
configuration.desktopIdeImage = choose.desktopIdeImage;
641+
configuration.ideConfig!.desktopIdeAlias = choose.desktopIdeAlias;
634642
}
635643

636644
const referrerIde = this.resolveReferrerIDE(workspace, user, ideConfig);
637645
if (referrerIde) {
638646
configuration.desktopIdeImage = useLatest
639647
? referrerIde.option.latestImage ?? referrerIde.option.image
640648
: referrerIde.option.image;
649+
configuration.ideConfig!.desktopIdeAlias = referrerIde.id;
641650
if (!user.additionalData?.ideSettings) {
642651
// A user does not have IDE settings configured yet configure it with a referrer ide as default.
643652
const additionalData = user?.additionalData || {};
@@ -654,6 +663,7 @@ export class WorkspaceStarter {
654663
});
655664
}
656665
}
666+
//#endregion
657667

658668
let featureFlags: NamedWorkspaceFeatureFlag[] = workspace.config._featureFlags || [];
659669
featureFlags = featureFlags.concat(this.config.workspaceDefaults.defaultFeatureFlags);
@@ -706,6 +716,7 @@ export class WorkspaceStarter {
706716
return instance;
707717
}
708718

719+
// TODO(ak) move to IDE service
709720
protected resolveReferrerIDE(
710721
workspace: Workspace,
711722
user: User,
@@ -1129,12 +1140,13 @@ export class WorkspaceStarter {
11291140
envvars.push(contextEnv);
11301141

11311142
log.debug("Workspace config", workspace.config);
1132-
if (!!workspace.config.tasks) {
1133-
// The task config is interpreted by Theia only, there's little point in transforming it into something
1143+
const tasks = this.ideService.resolveGitpodTasks(workspace, instance);
1144+
if (tasks.length) {
1145+
// The task config is interpreted by supervisor only, there's little point in transforming it into something
11341146
// wsman understands and back into the very same structure.
11351147
const ev = new EnvironmentVariable();
11361148
ev.setName("GITPOD_TASKS");
1137-
ev.setValue(JSON.stringify(workspace.config.tasks));
1149+
ev.setValue(JSON.stringify(tasks));
11381150
envvars.push(ev);
11391151
}
11401152

0 commit comments

Comments
 (0)