|
|
@ -3,9 +3,10 @@ import { readFile } from 'fs';
|
|
|
|
import { parse as parseJsonc, ParseError } from 'jsonc-parser';
|
|
|
|
import { parse as parseJsonc, ParseError } from 'jsonc-parser';
|
|
|
|
import * as path from 'path';
|
|
|
|
import * as path from 'path';
|
|
|
|
import { Client, ClientChannel, ConnectConfig } from 'ssh2';
|
|
|
|
import { Client, ClientChannel, ConnectConfig } from 'ssh2';
|
|
|
|
|
|
|
|
import { SFTPStream } from 'ssh2-streams';
|
|
|
|
import * as vscode from 'vscode';
|
|
|
|
import * as vscode from 'vscode';
|
|
|
|
import { getConfig, loadConfigs, openConfigurationEditor, updateConfig } from './config';
|
|
|
|
import { getConfig, loadConfigs, openConfigurationEditor, updateConfig } from './config';
|
|
|
|
import { createSocket, createSSH } from './connect';
|
|
|
|
import { createSocket, createSSH, getSFTP } from './connect';
|
|
|
|
import SSHFileSystem, { EMPTY_FILE_SYSTEM } from './sshFileSystem';
|
|
|
|
import SSHFileSystem, { EMPTY_FILE_SYSTEM } from './sshFileSystem';
|
|
|
|
import { MemoryDuplex } from './streams';
|
|
|
|
import { MemoryDuplex } from './streams';
|
|
|
|
import { catchingPromise, toPromise } from './toPromise';
|
|
|
|
import { catchingPromise, toPromise } from './toPromise';
|
|
|
@ -31,6 +32,7 @@ export interface FileSystemConfig extends ConnectConfig {
|
|
|
|
proxy?: ProxyConfig;
|
|
|
|
proxy?: ProxyConfig;
|
|
|
|
privateKeyPath?: string;
|
|
|
|
privateKeyPath?: string;
|
|
|
|
hop?: string;
|
|
|
|
hop?: string;
|
|
|
|
|
|
|
|
sftpCommand?: string;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export enum ConfigStatus {
|
|
|
|
export enum ConfigStatus {
|
|
|
@ -194,35 +196,29 @@ export class Manager implements vscode.FileSystemProvider, vscode.TreeDataProvid
|
|
|
|
}
|
|
|
|
}
|
|
|
|
root = root.replace(/^~/, home.replace(/\/$/, ''));
|
|
|
|
root = root.replace(/^~/, home.replace(/\/$/, ''));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
client.sftp(async (err, sftp) => {
|
|
|
|
const sftp = await getSFTP(client, config);
|
|
|
|
if (err) {
|
|
|
|
const fs = new SSHFileSystem(name, sftp, root, config!);
|
|
|
|
client.end();
|
|
|
|
try {
|
|
|
|
return reject(err);
|
|
|
|
const rootUri = vscode.Uri.parse(`ssh://${name}/`);
|
|
|
|
|
|
|
|
const stat = await fs.stat(rootUri);
|
|
|
|
|
|
|
|
// tslint:disable-next-line:no-bitwise
|
|
|
|
|
|
|
|
if (!(stat.type & vscode.FileType.Directory)) {
|
|
|
|
|
|
|
|
throw vscode.FileSystemError.FileNotADirectory(rootUri);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sftp.once('end', () => client.end());
|
|
|
|
} catch (e) {
|
|
|
|
const fs = new SSHFileSystem(name, sftp, root, config!);
|
|
|
|
let message = `Couldn't read the root directory '${fs.root}' on the server for SSH FS '${name}'`;
|
|
|
|
try {
|
|
|
|
if (e instanceof vscode.FileSystemError) {
|
|
|
|
const rootUri = vscode.Uri.parse(`ssh://${name}/`);
|
|
|
|
message = `Path '${fs.root}' in SSH FS '${name}' is not a directory`;
|
|
|
|
const stat = await fs.stat(rootUri);
|
|
|
|
|
|
|
|
// tslint:disable-next-line:no-bitwise
|
|
|
|
|
|
|
|
if (!(stat.type & vscode.FileType.Directory)) {
|
|
|
|
|
|
|
|
throw vscode.FileSystemError.FileNotADirectory(rootUri);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
|
|
let message = `Couldn't read the root directory '${fs.root}' on the server for SSH FS '${name}'`;
|
|
|
|
|
|
|
|
if (e instanceof vscode.FileSystemError) {
|
|
|
|
|
|
|
|
message = `Path '${fs.root}' in SSH FS '${name}' is not a directory`;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
await vscode.window.showErrorMessage(message, 'Okay');
|
|
|
|
|
|
|
|
return reject();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.fileSystems.push(fs);
|
|
|
|
await vscode.window.showErrorMessage(message, 'Okay');
|
|
|
|
delete this.creatingFileSystems[name];
|
|
|
|
return reject();
|
|
|
|
vscode.commands.executeCommand('workbench.files.action.refreshFilesExplorer');
|
|
|
|
}
|
|
|
|
this.onDidChangeTreeDataEmitter.fire();
|
|
|
|
this.fileSystems.push(fs);
|
|
|
|
client.once('close', hadError => hadError ? this.commandReconnect(name) : (!fs.closing && this.promptReconnect(name)));
|
|
|
|
delete this.creatingFileSystems[name];
|
|
|
|
return resolve(fs);
|
|
|
|
vscode.commands.executeCommand('workbench.files.action.refreshFilesExplorer');
|
|
|
|
});
|
|
|
|
this.onDidChangeTreeDataEmitter.fire();
|
|
|
|
|
|
|
|
client.once('close', hadError => hadError ? this.commandReconnect(name) : (!fs.closing && this.promptReconnect(name)));
|
|
|
|
|
|
|
|
return resolve(fs);
|
|
|
|
}).catch((e) => {
|
|
|
|
}).catch((e) => {
|
|
|
|
this.onDidChangeTreeDataEmitter.fire();
|
|
|
|
this.onDidChangeTreeDataEmitter.fire();
|
|
|
|
if (!e) {
|
|
|
|
if (!e) {
|
|
|
|