Skip to content
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,41 @@ sudo apk add bash libstdc++
## SSH configuration file

[OpenSSH](https://www.openssh.com/) supports using a [configuration file](https://linuxize.com/post/using-the-ssh-config-file/) to store all your different SSH connections. To use an SSH config file, run the `Remote-SSH: Open SSH Configuration File...` command.

## Note for VSCode-OSS users

If you are using VSCode-OSS instead of VSCodium, you need some extra steps to make it work.

Modify the following entries in the plugin settings:

```
"remote.SSH.experimental.modifyMatchingCommit": true,
"remote.SSH.experimental.serverBinaryName": "codium-server",
"remote.SSH.serverDownloadUrlTemplate": "https://github.com/VSCodium/vscodium/releases/download/${version}${release}/vscodium-reh-${os}-${arch}-${version}${release}.tar.gz",
```

Additionally, you may need to change the `vscodiumReleaseNumber`.
VSCodium versions have an extra `release` part that do not have equivalent for VSCode-OSS.
The plugin will use the latest release of the corresponding version. If you need to use another
VSCodium release, look for the release numbers associated with your VSCode version in the
[release page](https://github.com/VSCodium/vscodium/releases/).
For instance, for VSCode version "1.96.0", the (last) VSCodium release number is "24352".

In the plugin settings, modify the following entry to specify a particular release:

```
"remote.SSH.experimental.vscodiumReleaseNumber": "<vscodium-release>",
```

If left empty, it will pick the latest release:

```
"remote.SSH.experimental.vscodiumReleaseNumber": "",
```

Starting with VSCodium version 1.99.0, the `release` number is not separated from the `version` by a dot `.` anymore. Therefore "remote.SSH.serverDownloadUrlTemplate" needs to be filled with the new scheme.
Before 1.99.0, it can be left empty or one should use the old scheme:

```
"remote.SSH.serverDownloadUrlTemplate": "https://github.com/VSCodium/vscodium/releases/download/${version}.${release}/vscodium-reh-${os}-${arch}-${version}.${release}.tar.gz",
```
15 changes: 14 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,18 @@
"description": "**Experimental:** The name of the server binary, use this **only if** you are using a client without a corresponding server release",
"scope": "application",
"default": ""
},
"remote.SSH.experimental.vscodiumReleaseNumber": {
"type": "string",
"description": "**Experimental:** The VSCodium specific release number to use with serverDownloadUrlTemplate, automatic if left empty.",
"scope": "application",
"default": ""
},
"remote.SSH.experimental.modifyMatchingCommit": {
"type": "boolean",
"description": "**Experimental:** When true, modify the commit value of the remote server to match the local host.",
"scope": "application",
"default": false
}
}
},
Expand Down Expand Up @@ -360,10 +372,11 @@
"webpack-cli": "^4.7.2"
},
"dependencies": {
"@jeanp413/ssh-config": "^4.3.1",
"glob": "^9.3.1",
"node-fetch": "^3.3.2",
"simple-socks": "git+https://github.com/jeanp413/simple-socks#main",
"socks": "^2.5.0",
"@jeanp413/ssh-config": "^4.3.1",
"ssh2": "git+https://github.com/jeanp413/ssh2#master"
}
}
46 changes: 46 additions & 0 deletions src/fetchRelease.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import fetch from 'node-fetch';
import Log from './common/logger';


interface githubReleasesData {
name: string;
}

export async function fetchRelease(version: string, logger: Log, prefix: string = '.'): Promise<string> {

// Fetch github releases following: https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28
logger.info('Fetch the last release number of VSCodium corresponding to version ' + version);

let release = '';
try {
const response = await fetch("https://api.github.com/repos/VSCodium/vscodium/releases", {
method: "GET",
headers: {
"Content-Type": "application/json",
"Accept": "application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28",
},
});
const data = await response.json() as Array<githubReleasesData>;
let fullVersion: string;
for (let releaseInfo of data) {
fullVersion = releaseInfo.name;
if (fullVersion.startsWith(version)) {
logger.info('found release version: ' + fullVersion);

// Found a version match, it is the newer
// Remove the version: 1.96.4.25026 -> .25026
release = fullVersion.slice(version.length);
// Remove the prefix dot '.', if present: 1.96.4.25026 -> 25026 or 1.99.02277 -> 2277
if (release.startsWith(prefix)) {
release = release.slice(prefix.length)
}
break;
}
}
} catch (error) {
logger.error('Error fetching releases:', error);
}

return release;
}
25 changes: 19 additions & 6 deletions src/serverConfig.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import * as vscode from 'vscode';
import * as fs from 'fs';
import * as path from 'path';
import { fetchRelease } from './fetchRelease';
import Log from './common/logger';

let vscodeProductJson: any;
async function getVSCodeProductJson() {
Expand All @@ -16,24 +18,35 @@ export interface IServerConfig {
version: string;
commit: string;
quality: string;
release?: string; // vscodium-like specific
release?: string;
serverApplicationName: string;
serverDataFolderName: string;
serverDownloadUrlTemplate?: string; // vscodium-like specific
serverDownloadUrlTemplate?: string;
modifyMatchingCommit: boolean;
}

export async function getVSCodeServerConfig(): Promise<IServerConfig> {
export async function getVSCodeServerConfig(logger: Log): Promise<IServerConfig> {
const productJson = await getVSCodeProductJson();

const customServerBinaryName = vscode.workspace.getConfiguration('remote.SSH.experimental').get<string>('serverBinaryName', '');
const customModifyMatchingCommit = vscode.workspace.getConfiguration('remote.SSH.experimental').get<boolean>('modifyMatchingCommit', false);

// Get release, if the option is provided or fetch it from the github releases
const version = vscode.version.replace('-insider','');
let customRelease = vscode.workspace.getConfiguration('remote.SSH.experimental').get<string>('vscodiumReleaseNumber', '');
customRelease = customRelease || productJson.release;
if (!customRelease) {
customRelease = await fetchRelease(version, logger);
}

return {
version: vscode.version.replace('-insider',''),
version: version,
commit: productJson.commit,
quality: productJson.quality,
release: productJson.release,
release: customRelease,
serverApplicationName: customServerBinaryName || productJson.serverApplicationName,
serverDataFolderName: productJson.serverDataFolderName,
serverDownloadUrlTemplate: productJson.serverDownloadUrlTemplate
serverDownloadUrlTemplate: productJson.serverDownloadUrlTemplate,
modifyMatchingCommit: customModifyMatchingCommit,
};
}
23 changes: 19 additions & 4 deletions src/serverSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ export interface ServerInstallOptions {
quality: string;
commit: string;
version: string;
release?: string; // vscodium specific
release?: string;
extensionIds: string[];
envVariables: string[];
useSocketPath: boolean;
serverApplicationName: string;
serverDataFolderName: string;
serverDownloadUrlTemplate: string;
modifyMatchingCommit: boolean;
}

export interface ServerInstallResult {
Expand Down Expand Up @@ -69,7 +70,7 @@ export async function installCodeServer(conn: SSHConnection, serverDownloadUrlTe

const scriptId = crypto.randomBytes(12).toString('hex');

const vscodeServerConfig = await getVSCodeServerConfig();
const vscodeServerConfig = await getVSCodeServerConfig(logger);
const installOptions: ServerInstallOptions = {
id: scriptId,
version: vscodeServerConfig.version,
Expand All @@ -82,6 +83,7 @@ export async function installCodeServer(conn: SSHConnection, serverDownloadUrlTe
serverApplicationName: vscodeServerConfig.serverApplicationName,
serverDataFolderName: vscodeServerConfig.serverDataFolderName,
serverDownloadUrlTemplate: serverDownloadUrlTemplate || vscodeServerConfig.serverDownloadUrlTemplate || DEFAULT_DOWNLOAD_URL_TEMPLATE,
modifyMatchingCommit: vscodeServerConfig.modifyMatchingCommit,
};

let commandOutput: { stdout: string; stderr: string };
Expand Down Expand Up @@ -198,7 +200,7 @@ function parseServerInstallOutput(str: string, scriptId: string): { [k: string]:
return resultMap;
}

function generateBashInstallScript({ id, quality, version, commit, release, extensionIds, envVariables, useSocketPath, serverApplicationName, serverDataFolderName, serverDownloadUrlTemplate }: ServerInstallOptions) {
function generateBashInstallScript({ id, quality, version, commit, release, extensionIds, envVariables, useSocketPath, serverApplicationName, serverDataFolderName, serverDownloadUrlTemplate, modifyMatchingCommit }: ServerInstallOptions) {
const extensions = extensionIds.map(id => '--install-extension ' + id).join(' ');
return `
# Server installation script
Expand Down Expand Up @@ -365,6 +367,12 @@ else
echo "Server script already installed in $SERVER_SCRIPT"
fi

# Make sure the commits match
if ${modifyMatchingCommit ? 'true' : 'false'}; then
echo "Will modify product.json on remote to match the commit value"
sed -i -E 's/"commit": "[0-9a-f]+",/"commit": "'"$DISTRO_COMMIT"'",/' "$SERVER_DIR/product.json"
fi

# Try to find if server is already running
if [[ -f $SERVER_PIDFILE ]]; then
SERVER_PID="$(cat $SERVER_PIDFILE)"
Expand Down Expand Up @@ -422,7 +430,7 @@ print_install_results_and_exit 0
`;
}

function generatePowerShellInstallScript({ id, quality, version, commit, release, extensionIds, envVariables, useSocketPath, serverApplicationName, serverDataFolderName, serverDownloadUrlTemplate }: ServerInstallOptions) {
function generatePowerShellInstallScript({ id, quality, version, commit, release, extensionIds, envVariables, useSocketPath, serverApplicationName, serverDataFolderName, serverDownloadUrlTemplate, modifyMatchingCommit }: ServerInstallOptions) {
const extensions = extensionIds.map(id => '--install-extension ' + id).join(' ');
const downloadUrl = serverDownloadUrlTemplate
.replace(/\$\{quality\}/g, quality)
Expand Down Expand Up @@ -534,6 +542,13 @@ else {
"Server script already installed in $SERVER_SCRIPT"
}

# Make sure the commits match
if(${modifyMatchingCommit ? '$true' : '$false'}) {
echo "Will modify product.json on remote to match the commit value"
(Get-Content -Raw "$SERVER_DIR\\product.json") -replace '"commit": "[0-9a-f]+",', ('"commit": "' + $DISTRO_COMMIT + '",') |
Set-Content -NoNewLine "$SERVER_DIR\\product.json"
}

# Try to find if server is already running
if(Get-Process node -ErrorAction SilentlyContinue | Where-Object Path -Like "$SERVER_DIR\\*") {
echo "Server script is already running $SERVER_SCRIPT"
Expand Down
Loading