Skip to content

Commit ec81137

Browse files
committed
Improve remote application cache
1 parent eb3d863 commit ec81137

File tree

1 file changed

+24
-12
lines changed

1 file changed

+24
-12
lines changed

packages/remote/src/node/remote-setup-service.ts

+24-12
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { RemoteConnection, RemoteExecResult, RemotePlatform, RemoteStatusReport
2323
import { ApplicationPackage } from '@theia/core/shared/@theia/application-package';
2424
import { RemoteCopyService } from './remote-copy-service';
2525
import { RemoteNativeDependencyService } from './remote-native-dependency-service';
26+
import { THEIA_VERSION } from '@theia/core';
2627

2728
/**
2829
* The current node version that Theia recommends.
@@ -50,14 +51,14 @@ export class RemoteSetupService {
5051
report('Identifying remote system...');
5152
// 1. Identify remote platform
5253
const platform = await this.detectRemotePlatform(connection);
53-
// Build a few remote system paths
54+
// 2. Setup home directory
5455
const remoteHome = await this.getRemoteHomeDirectory(connection, platform);
5556
const applicationDirectory = this.joinRemotePath(platform, remoteHome, `.${this.getRemoteAppName()}`);
5657
await this.mkdirRemote(connection, platform, applicationDirectory);
58+
// 3. Download+copy node for that platform
5759
const nodeFileName = this.getNodeFileName(platform);
5860
const nodeDirName = this.getNodeDirectoryName(platform);
5961
const remoteNodeDirectory = this.joinRemotePath(platform, applicationDirectory, nodeDirName);
60-
// 2. Download+copy node for that platform
6162
const nodeDirExists = await this.dirExistsRemote(connection, remoteNodeDirectory);
6263
if (!nodeDirExists) {
6364
report('Downloading and installing Node.js on remote...');
@@ -66,12 +67,16 @@ export class RemoteSetupService {
6667
await connection.copy(nodeArchive, remoteNodeZip);
6768
await this.unzipRemote(connection, remoteNodeZip, applicationDirectory);
6869
}
69-
// 3. Copy backend to remote system
70+
// 4. Copy backend to remote system
7071
report('Copying application to remote...');
71-
const applicationZipFile = this.joinRemotePath(platform, applicationDirectory, `${this.getRemoteAppName()}.tar`);
72-
await this.copyService.copyToRemote(connection, platform, applicationZipFile);
73-
await this.unzipRemote(connection, applicationZipFile, applicationDirectory);
74-
// 4. start remote backend
72+
const libDir = this.joinRemotePath(platform, applicationDirectory, 'lib');
73+
const libDirExists = await this.dirExistsRemote(connection, libDir);
74+
if (!libDirExists) {
75+
const applicationZipFile = this.joinRemotePath(platform, applicationDirectory, `${this.getRemoteAppName()}.tar`);
76+
await this.copyService.copyToRemote(connection, platform, applicationZipFile);
77+
await this.unzipRemote(connection, applicationZipFile, applicationDirectory);
78+
}
79+
// 5. start remote backend
7580
report('Starting application on remote...');
7681
const port = await this.startApplication(connection, platform, applicationDirectory, remoteNodeDirectory);
7782
connection.remotePort = port;
@@ -162,7 +167,9 @@ export class RemoteSetupService {
162167
}
163168

164169
protected getRemoteAppName(): string {
165-
return `${this.cleanupDirectoryName(this.applicationPackage.pck.name || 'theia')}-remote`;
170+
const appName = this.applicationPackage.pck.name || 'theia';
171+
const appVersion = this.applicationPackage.pck.version || THEIA_VERSION;
172+
return `${this.cleanupDirectoryName(`${appName}-${appVersion}`)}-remote`;
166173
}
167174

168175
protected cleanupDirectoryName(name: string): string {
@@ -176,15 +183,15 @@ export class RemoteSetupService {
176183

177184
protected async mkdirRemote(connection: RemoteConnection, platform: RemotePlatform, remotePath: string): Promise<void> {
178185
const recursive = platform !== 'windows' ? ' -p' : '';
179-
const result = await connection.exec(`mkdir${recursive}`, [remotePath]);
186+
const result = await this.retry(() => connection.exec(`mkdir${recursive} "${remotePath}";echo "Success"`));
180187
if (result.stderr) {
181188
throw new Error('Failed to create directory: ' + result.stderr);
182189
}
183190
}
184191

185192
protected async dirExistsRemote(connection: RemoteConnection, remotePath: string): Promise<boolean> {
186-
const cdResult = await connection.exec('cd', [remotePath]);
187-
return !Boolean(cdResult.stderr);
193+
const cdResult = await this.retry(() => connection.exec(`cd "${remotePath}";echo "Success"`));
194+
return Boolean(cdResult.stdout);
188195
}
189196

190197
protected async unzipRemote(connection: RemoteConnection, remoteFile: string, remoteDirectory: string): Promise<void> {
@@ -194,7 +201,12 @@ export class RemoteSetupService {
194201
}
195202
}
196203

197-
protected async retry(action: () => Promise<RemoteExecResult>, times = 10): Promise<RemoteExecResult> {
204+
/**
205+
* Sometimes, ssh2.exec will not execute and retrieve any data.
206+
* For this case, we just perform the exec call multiple times until we get something back.
207+
* See also https://github.com/mscdex/ssh2/issues/48
208+
*/
209+
protected async retry(action: () => Promise<RemoteExecResult>, times = 20): Promise<RemoteExecResult> {
198210
let result: RemoteExecResult = { stderr: '', stdout: '' };
199211
while (times-- > 0) {
200212
result = await action();

0 commit comments

Comments
 (0)