Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support SSH remote development feature #12618

Merged
merged 12 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions .github/workflows/native-dependencies.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Package Native Dependencies

on: workflow_dispatch

jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: ['ubuntu-20.04', 'windows-latest', 'macos-latest']
steps:
- name: Checkout
uses: actions/checkout@v3

# Update the node version here after every Electron upgrade
- name: Use Node.js 18.17.0
uses: actions/setup-node@v3
with:
node-version: '18.17.0'
registry-url: 'https://registry.npmjs.org'

- name: Use Python 3.11
uses: actions/setup-python@v4
with:
python-version: '3.11'

- name: Install and Build
shell: bash
run: |
yarn --skip-integrity-check --network-timeout 100000
env:
NODE_OPTIONS: --max_old_space_size=4096
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # https://github.com/microsoft/vscode-ripgrep/issues/9

- name: Build Browser App
shell: bash
run: |
yarn browser build
env:
NODE_OPTIONS: --max_old_space_size=4096

- name: Zip Native Dependencies
shell: bash
run: yarn zip:native:dependencies

- name: Upload Artifacts
uses: actions/upload-artifact@v3
with:
name: native-dependencies
path: ./scripts/native-dependencies-*.zip
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ dependency-check-summary.txt*
.tours
/performance-result.json
*.vsix
/scripts/native-dependencies-*
1 change: 1 addition & 0 deletions examples/browser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"@theia/preview": "1.42.0",
"@theia/process": "1.42.0",
"@theia/property-view": "1.42.0",
"@theia/remote": "1.42.0",
"@theia/scm": "1.42.0",
"@theia/scm-extra": "1.42.0",
"@theia/search-in-workspace": "1.42.0",
Expand Down
3 changes: 3 additions & 0 deletions examples/browser/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@
{
"path": "../../packages/property-view"
},
{
"path": "../../packages/remote"
},
{
"path": "../../packages/scm"
},
Expand Down
1 change: 1 addition & 0 deletions examples/electron/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"@theia/preview": "1.42.0",
"@theia/process": "1.42.0",
"@theia/property-view": "1.42.0",
"@theia/remote": "1.42.0",
"@theia/scm": "1.42.0",
"@theia/scm-extra": "1.42.0",
"@theia/search-in-workspace": "1.42.0",
Expand Down
3 changes: 3 additions & 0 deletions examples/electron/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@
{
"path": "../../packages/property-view"
},
{
"path": "../../packages/remote"
},
{
"path": "../../packages/scm"
},
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@typescript-eslint/eslint-plugin-tslint": "^4.8.1",
"@typescript-eslint/parser": "^4.8.1",
"@vscode/vsce": "^2.15.0",
"archiver": "^5.3.1",
"chai": "4.3.10",
"chai-spies": "1.0.0",
"chai-string": "^1.4.0",
Expand Down Expand Up @@ -90,7 +91,8 @@
"watch:compile": "concurrently --kill-others -n cleanup,tsc -c magenta,red \"ts-clean dev-packages/* packages/* -w\" \"tsc -b -w --preserveWatchOutput\"",
"performance:startup": "yarn -s performance:startup:browser && yarn -s performance:startup:electron",
"performance:startup:browser": "concurrently --success first -k -r \"cd scripts/performance && node browser-performance.js --name 'Browser Frontend Startup' --folder browser --runs 10\" \"yarn -s --cwd examples/browser start\"",
"performance:startup:electron": "yarn -s electron rebuild && cd scripts/performance && node electron-performance.js --name 'Electron Frontend Startup' --folder electron --runs 10"
"performance:startup:electron": "yarn -s electron rebuild && cd scripts/performance && node electron-performance.js --name 'Electron Frontend Startup' --folder electron --runs 10",
"zip:native:dependencies": "node ./scripts/zip-native-dependencies.js"
},
"workspaces": [
"dev-packages/*",
Expand Down
18 changes: 18 additions & 0 deletions packages/core/src/browser/common-frontend-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2300,6 +2300,24 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
hcLight: Color.lighten('statusBar.offlineBackground', 0.6)
}, description: 'Background of active statusbar item in case the theia server is offline.'
},
{
id: 'statusBarItem.remoteBackground',
defaults: {
dark: 'activityBarBadge.background',
light: 'activityBarBadge.background',
hcDark: 'activityBarBadge.background',
hcLight: 'activityBarBadge.background'
}, description: 'Background color for the remote indicator on the status bar.'
},
{
id: 'statusBarItem.remoteForeground',
defaults: {
dark: 'activityBarBadge.foreground',
light: 'activityBarBadge.foreground',
hcDark: 'activityBarBadge.foreground',
hcLight: 'activityBarBadge.foreground'
}, description: 'Foreground color for the remote indicator on the status bar.'
},
// Buttons
{
id: 'secondaryButton.foreground',
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/browser/credentials-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

import { inject, injectable } from 'inversify';
import { Emitter, Event } from '../common/event';
import { KeytarService } from '../common/keytar-protocol';
import { KeyStoreService } from '../common/key-store';

export interface CredentialsProvider {
getPassword(service: string, account: string): Promise<string | undefined>;
Expand Down Expand Up @@ -50,7 +50,7 @@ export class CredentialsServiceImpl implements CredentialsService {

private credentialsProvider: CredentialsProvider;

constructor(@inject(KeytarService) private readonly keytarService: KeytarService) {
constructor(@inject(KeyStoreService) private readonly keytarService: KeyStoreService) {
this.credentialsProvider = new KeytarCredentialsProvider(this.keytarService);
}

Expand Down Expand Up @@ -82,7 +82,7 @@ export class CredentialsServiceImpl implements CredentialsService {

class KeytarCredentialsProvider implements CredentialsProvider {

constructor(private readonly keytarService: KeytarService) { }
constructor(private readonly keytarService: KeyStoreService) { }

deletePassword(service: string, account: string): Promise<boolean> {
return this.keytarService.deletePassword(service, account);
Expand Down
12 changes: 6 additions & 6 deletions packages/core/src/browser/frontend-application-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ import { EncodingRegistry } from './encoding-registry';
import { EncodingService } from '../common/encoding-service';
import { AuthenticationService, AuthenticationServiceImpl } from '../browser/authentication-service';
import { DecorationsService, DecorationsServiceImpl } from './decorations-service';
import { keytarServicePath, KeytarService } from '../common/keytar-protocol';
import { keyStoreServicePath, KeyStoreService } from '../common/key-store';
import { CredentialsService, CredentialsServiceImpl } from './credentials-service';
import { ContributionFilterRegistry, ContributionFilterRegistryImpl } from '../common/contribution-filter';
import { QuickCommandFrontendContribution } from './quick-input/quick-command-frontend-contribution';
Expand Down Expand Up @@ -248,7 +248,7 @@ export const frontendApplicationModule = new ContainerModule((bind, _unbind, _is

bind(SelectionService).toSelf().inSingletonScope();
bind(CommandRegistry).toSelf().inSingletonScope().onActivation(({ container }, registry) => {
WebSocketConnectionProvider.createProxy(container, commandServicePath, registry);
WebSocketConnectionProvider.createHandler(container, commandServicePath, registry);
return registry;
});
bind(CommandService).toService(CommandRegistry);
Expand All @@ -268,7 +268,7 @@ export const frontendApplicationModule = new ContainerModule((bind, _unbind, _is

bindMessageService(bind).onActivation(({ container }, messages) => {
const client = container.get(MessageClient);
WebSocketConnectionProvider.createProxy(container, messageServicePath, client);
WebSocketConnectionProvider.createHandler(container, messageServicePath, client);
return messages;
});

Expand Down Expand Up @@ -296,7 +296,7 @@ export const frontendApplicationModule = new ContainerModule((bind, _unbind, _is
bind(QuickAccessContribution).toService(QuickHelpService);

bind(QuickPickService).to(QuickPickServiceImpl).inSingletonScope().onActivation(({ container }, quickPickService: QuickPickService) => {
WebSocketConnectionProvider.createProxy(container, quickPickServicePath, quickPickService);
WebSocketConnectionProvider.createHandler(container, quickPickServicePath, quickPickService);
return quickPickService;
});

Expand Down Expand Up @@ -399,9 +399,9 @@ export const frontendApplicationModule = new ContainerModule((bind, _unbind, _is
bind(AuthenticationService).to(AuthenticationServiceImpl).inSingletonScope();
bind(DecorationsService).to(DecorationsServiceImpl).inSingletonScope();

bind(KeytarService).toDynamicValue(ctx => {
bind(KeyStoreService).toDynamicValue(ctx => {
const connection = ctx.container.get(WebSocketConnectionProvider);
return connection.createProxy<KeytarService>(keytarServicePath);
return connection.createProxy<KeyStoreService>(keyStoreServicePath);
}).inSingletonScope();

bind(CredentialsService).to(CredentialsServiceImpl);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
// *****************************************************************************

import { ContainerModule } from 'inversify';
import { WebSocketConnectionProvider } from './ws-connection-provider';
import { LocalWebSocketConnectionProvider, WebSocketConnectionProvider } from './ws-connection-provider';

export const messagingFrontendModule = new ContainerModule(bind => {
bind(WebSocketConnectionProvider).toSelf().inSingletonScope();
bind(LocalWebSocketConnectionProvider).toService(WebSocketConnectionProvider);
});
23 changes: 21 additions & 2 deletions packages/core/src/browser/messaging/ws-connection-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import { IWebSocket, WebSocketChannel } from '../../common/messaging/web-socket-
decorate(injectable(), RpcProxyFactory);
decorate(unmanaged(), RpcProxyFactory, 0);

export const LocalWebSocketConnectionProvider = Symbol('LocalWebSocketConnectionProvider');

export interface WebSocketOptions {
/**
* True by default.
Expand All @@ -48,6 +50,19 @@ export class WebSocketConnectionProvider extends AbstractConnectionProvider<WebS
return container.get(WebSocketConnectionProvider).createProxy<T>(path, arg);
}

static createLocalProxy<T extends object>(container: interfaces.Container, path: string, arg?: object): RpcProxy<T> {
return container.get<WebSocketConnectionProvider>(LocalWebSocketConnectionProvider).createProxy<T>(path, arg);
}

static createHandler(container: interfaces.Container, path: string, arg?: object): void {
const remote = container.get(WebSocketConnectionProvider);
const local = container.get<WebSocketConnectionProvider>(LocalWebSocketConnectionProvider);
remote.createProxy(path, arg);
if (remote !== local) {
local.createProxy(path, arg);
}
}

protected readonly socket: Socket;

constructor() {
Expand Down Expand Up @@ -104,11 +119,15 @@ export class WebSocketConnectionProvider extends AbstractConnectionProvider<WebS
protected createWebSocketUrl(path: string): string {
// Since we are using Socket.io, the path should look like the following:
// proto://domain.com/{path}
return new Endpoint().getWebSocketUrl().withPath(path).toString();
return this.createEndpoint(path).getWebSocketUrl().toString();
}

protected createHttpWebSocketUrl(path: string): string {
return new Endpoint({ path }).getRestUrl().toString();
return this.createEndpoint(path).getRestUrl().toString();
}

protected createEndpoint(path: string): Endpoint {
return new Endpoint({ path });
}

/**
Expand Down
8 changes: 6 additions & 2 deletions packages/core/src/browser/status-bar/status-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ export class StatusBarImpl extends ReactWidget implements StatusBar {
} else {
attrs['aria-label'] = [entry.text, entry.tooltip].join(', ');
}
if (entry.backgroundColor) {
attrs.className += ' has-background';
}

attrs.style = {
color: entry.color || this.color,
Expand Down Expand Up @@ -178,8 +181,9 @@ export class StatusBarImpl extends ReactWidget implements StatusBar {
children.push(<span key={key}>{val}</span>);
}
});
const elementInnerDiv = <React.Fragment>{children}</React.Fragment>;
return React.createElement('div', { key: entry.id, ...this.createAttributes(entry) }, elementInnerDiv);
return <div key={entry.id} {...this.createAttributes(entry)}>
{children}
</div>;
}

}
16 changes: 12 additions & 4 deletions packages/core/src/browser/style/status-bar.css
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ body.theia-no-open-workspace #theia-statusBar {
background: var(--theia-statusBar-noFolderBackground);
color: var(--theia-statusBar-noFolderForeground);
border-top: var(--theia-border-width) solid
var(--theia-statusBar-noFolderBorder);
var(--theia-statusBar-noFolderBorder);
}

#theia-statusBar .area {
Expand All @@ -41,7 +41,6 @@ body.theia-no-open-workspace #theia-statusBar {

#theia-statusBar .area.left {
justify-content: flex-start;
padding-left: calc(var(--theia-ui-padding) * 2);
}

#theia-statusBar .area.right {
Expand All @@ -56,8 +55,14 @@ body.theia-no-open-workspace #theia-statusBar {
font-size: var(--theia-statusBar-font-size);
}

#theia-statusBar .area .element > * {
margin-left: calc(var(--theia-ui-padding) / 2);
#theia-statusBar .area.left .element.has-background {
margin-left: 0px;
margin-right: 3px;
padding-left: 7px;
padding-right: 7px;
}
#theia-statusBar .area .element>* {
margin-left: calc(var(--theia-ui-padding)/2);
}

#theia-statusBar .area .element .codicon {
Expand All @@ -77,6 +82,9 @@ body.theia-no-open-workspace #theia-statusBar {
color: var(--theia-statusBar-offlineForeground) !important;
}

#theia-statusBar .area.left .element:first-child:not(.has-background) {
margin-left: calc(var(--theia-ui-padding) * 3);
}
#theia-statusBar .area.left .element {
margin-right: var(--theia-ui-padding);
}
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/browser/window/window-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import { StopReason } from '../../common/frontend-application-state';
import { Event } from '../../common/event';
import { NewWindowOptions } from '../../common/window';
import { NewWindowOptions, WindowSearchParams } from '../../common/window';

/**
* Service for opening new browser windows.
Expand All @@ -35,7 +35,7 @@ export interface WindowService {
* Opens a new default window.
* - In electron and in the browser it will open the default window without a pre-defined content.
*/
openNewDefaultWindow(): void;
openNewDefaultWindow(params?: WindowSearchParams): void;

/**
* Fires when the `window` unloads. The unload event is inevitable. On this event, the frontend application can save its state and release resource.
Expand Down Expand Up @@ -64,5 +64,5 @@ export interface WindowService {
/**
* Reloads the window according to platform.
*/
reload(): void;
reload(params?: WindowSearchParams): void;
}
1 change: 1 addition & 0 deletions packages/core/src/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,4 @@ export * from './telemetry';
export * from './types';
export { default as URI } from './uri';
export * from './view-column';
export * from './version';
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************

export const keytarServicePath = '/services/keytar';
export const keyStoreServicePath = '/services/keyStore';

export const KeytarService = Symbol('KeytarService');
export interface KeytarService {
export const KeyStoreService = Symbol('KeyStoreService');
export interface KeyStoreService {
setPassword(service: string, account: string, password: string): Promise<void>;
getPassword(service: string, account: string): Promise<string | undefined>;
deletePassword(service: string, account: string): Promise<boolean>;
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/common/quick-pick-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ export interface QuickPickOptions<T extends QuickPickItemOrSeparator> {
onDidTriggerItemButton?: (ItemButtonEvent: QuickPickItemButtonContext<T>) => void
}

export const quickInputServicePath = '/services/quickInput';
tsmaeder marked this conversation as resolved.
Show resolved Hide resolved
export const QuickInputService = Symbol('QuickInputService');
export interface QuickInputService {
readonly backButton: QuickInputButton;
Expand Down
Loading