Update to ssh2@^1.6.0.0

pull/373/head
Kelvin Schoofs 3 years ago
parent 85f7a69c46
commit 2e1470989b

@ -2375,7 +2375,7 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/experimental-utils@npm:4.33.0":
"@typescript-eslint/experimental-utils@npm:4.33.0, @typescript-eslint/experimental-utils@npm:^4.0.1":
version: 4.33.0
resolution: "@typescript-eslint/experimental-utils@npm:4.33.0"
dependencies:
@ -2406,22 +2406,6 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/experimental-utils@npm:^4.0.1":
version: 4.29.2
resolution: "@typescript-eslint/experimental-utils@npm:4.29.2"
dependencies:
"@types/json-schema": ^7.0.7
"@typescript-eslint/scope-manager": 4.29.2
"@typescript-eslint/types": 4.29.2
"@typescript-eslint/typescript-estree": 4.29.2
eslint-scope: ^5.1.1
eslint-utils: ^3.0.0
peerDependencies:
eslint: "*"
checksum: e07b6b58f386ba84801d10bfe494548c3af20448c2f5596b77d13ba8621345ced4e1c6cf946dcf118c1e8566e0eed8284200f3f3a96f89aa7f367d9cdf6549a3
languageName: node
linkType: hard
"@typescript-eslint/parser@npm:^4.5.0":
version: 4.33.0
resolution: "@typescript-eslint/parser@npm:4.33.0"
@ -2439,16 +2423,6 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/scope-manager@npm:4.29.2":
version: 4.29.2
resolution: "@typescript-eslint/scope-manager@npm:4.29.2"
dependencies:
"@typescript-eslint/types": 4.29.2
"@typescript-eslint/visitor-keys": 4.29.2
checksum: f89d11cf7ce28c37a913db432d3dd2c4e5f5bc431bac205dd55c3d49704be691a28d5f27ae96fde7feee23d3e80192d7aff3d8350aef53b415e5b0b53cd965d7
languageName: node
linkType: hard
"@typescript-eslint/scope-manager@npm:4.33.0":
version: 4.33.0
resolution: "@typescript-eslint/scope-manager@npm:4.33.0"
@ -2466,13 +2440,6 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/types@npm:4.29.2":
version: 4.29.2
resolution: "@typescript-eslint/types@npm:4.29.2"
checksum: 0bcab66bb1848e2361bb366abebe1f94baa56d7d2058b62467f14c054b969b72d1aa17717a52c11f48e9cfb50846f0e227e49ccc7f06ff750b9eb28ca8b064de
languageName: node
linkType: hard
"@typescript-eslint/types@npm:4.33.0":
version: 4.33.0
resolution: "@typescript-eslint/types@npm:4.33.0"
@ -2499,24 +2466,6 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/typescript-estree@npm:4.29.2":
version: 4.29.2
resolution: "@typescript-eslint/typescript-estree@npm:4.29.2"
dependencies:
"@typescript-eslint/types": 4.29.2
"@typescript-eslint/visitor-keys": 4.29.2
debug: ^4.3.1
globby: ^11.0.3
is-glob: ^4.0.1
semver: ^7.3.5
tsutils: ^3.21.0
peerDependenciesMeta:
typescript:
optional: true
checksum: 90342d27f3f0837ad39f9b7e7d7c3c0b6de9c5b0770f5a18d490ebaf7be78efa65ba46ce0ca3004ad946ca1adc5865c5d3ba3b049c95b3b193bfdf0eb5e23095
languageName: node
linkType: hard
"@typescript-eslint/typescript-estree@npm:4.33.0":
version: 4.33.0
resolution: "@typescript-eslint/typescript-estree@npm:4.33.0"
@ -2544,16 +2493,6 @@ __metadata:
languageName: node
linkType: hard
"@typescript-eslint/visitor-keys@npm:4.29.2":
version: 4.29.2
resolution: "@typescript-eslint/visitor-keys@npm:4.29.2"
dependencies:
"@typescript-eslint/types": 4.29.2
eslint-visitor-keys: ^2.0.0
checksum: 34185d8c6466340aba746d69b36d357da2d06577d73f58358648c142bd0f181d7fae01ca1138188a665ef074ea7e1bc6306ef9d50f29914c8bcea4e9ea1f82f2
languageName: node
linkType: hard
"@typescript-eslint/visitor-keys@npm:4.33.0":
version: 4.33.0
resolution: "@typescript-eslint/visitor-keys@npm:4.33.0"
@ -3102,7 +3041,7 @@ __metadata:
languageName: node
linkType: hard
"asn1@npm:~0.2.0":
"asn1@npm:^0.2.4":
version: 0.2.6
resolution: "asn1@npm:0.2.6"
dependencies:
@ -3859,6 +3798,13 @@ __metadata:
languageName: node
linkType: hard
"cpu-features@npm:@favware/skip-dependency@1.1.3":
version: 1.1.3
resolution: "@favware/skip-dependency@npm:1.1.3"
checksum: 052e94745f83e799b676cc711a23b6112cc7aecdd6ed157bb9be85fa5ce032c100f591f0c66e1e7383bcab5743ec40179bed0ff52ed809d9d191a5c9321e4da2
languageName: node
linkType: hard
"cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3":
version: 7.0.3
resolution: "cross-spawn@npm:7.0.3"
@ -6711,6 +6657,15 @@ fsevents@~2.3.2:
languageName: node
linkType: hard
"nan@npm:^2.15.0":
version: 2.15.0
resolution: "nan@npm:2.15.0"
dependencies:
node-gyp: latest
checksum: 33e1bb4dfca447fe37d4bb5889be55de154828632c8d38646db67293a21afd61ed9909cdf1b886214a64707d935926c4e60e2b09de9edfc2ad58de31d6ce8f39
languageName: node
linkType: hard
"nanoid@npm:^3.2.0":
version: 3.3.1
resolution: "nanoid@npm:3.3.1"
@ -8727,23 +8682,20 @@ resolve@^2.0.0-next.3:
languageName: node
linkType: hard
"ssh2-streams@Timmmm/ssh2-streams#patch-1":
version: 0.4.10
resolution: "ssh2-streams@https://github.com/Timmmm/ssh2-streams.git#commit=75f6d3425d071ac73a18fd46e2f5e738bfe897c5"
"ssh2@npm:^1.6.0":
version: 1.6.0
resolution: "ssh2@npm:1.6.0"
dependencies:
asn1: ~0.2.0
asn1: ^0.2.4
bcrypt-pbkdf: ^1.0.2
streamsearch: ~0.1.2
checksum: d0a5671f88e87fc85783c18cf99001315771dd313452643063fec5edbe4d223e7204f64e58177b4e9a11f9d6406e3988c16a33cc9463817b25a5afcfee1f0245
languageName: node
linkType: hard
"ssh2@npm:^0.8.9":
version: 0.8.9
resolution: "ssh2@npm:0.8.9"
dependencies:
ssh2-streams: ~0.4.10
checksum: 3127497cb5570922b3c37daf93e1e49e24776ae3046c7e01c4af1323408653267ea7d9e506283adbdc8445cd20429318501e08db75f2101bbb0bdc49455da720
cpu-features: 0.0.2
nan: ^2.15.0
dependenciesMeta:
cpu-features:
optional: true
nan:
optional: true
checksum: a0bed1463729e7b1bb2b9e2381cb3b12e3b759c2416a666e0218825fa9eaae440676dc54c151e86186ec9e9d02a283938c7234ebdfc2d29976dd1d137e70cb23
languageName: node
linkType: hard
@ -8787,13 +8739,6 @@ resolve@^2.0.0-next.3:
languageName: node
linkType: hard
"streamsearch@npm:~0.1.2":
version: 0.1.2
resolution: "streamsearch@npm:0.1.2"
checksum: d2db57cbfbf7947ab9c75a7b4c80a8ef8d24850cf0a1a24258bb6956c97317ce1eab7dbcbf9c5aba3e6198611af1053b02411057bbedb99bf9c64b8275248997
languageName: node
linkType: hard
"strict-uri-encode@npm:^1.0.0":
version: 1.1.0
resolution: "strict-uri-encode@npm:1.1.0"
@ -9511,7 +9456,6 @@ resolve@^2.0.0-next.3:
"@types/node": ^12.7.12
"@types/request": ^2.48.1
"@types/semver": ^7.3.9
"@types/ssh2": ^0.5.41
"@types/vscode": ~1.49.0
"@types/webpack": ^4.4.25
"@types/winreg": ^1.2.30
@ -9522,8 +9466,7 @@ resolve@^2.0.0-next.3:
socks: ^2.2.0
source-map: ^0.7.3
source-map-support: ^0.5.19
ssh2: ^0.8.9
ssh2-streams: ^0.4.10
ssh2: ^1.6.0
ts-loader: ^9.2.3
typescript: ~4.5.5
vsce: ^2.5.1

@ -3,6 +3,15 @@
## Unreleased
### Major change
- Updated from `ssh2@0.8.9` to `ssh@1.6.0`
- Part of this update forces me to ditch `ssh2-streams` which played a major role for SFTP
- The `ssh2` package has a built-in but unexposed alternative we can more or less use directly
- The `@types/ssh2` is semi-outdated and has lots of inaccuracies, along with missing internal things
- For this major update a `ssh2.ts` replacing `@types/ssh2` is added to the `common` module
- This does pull in a lot of new fixes/features added since `ssh2@1.0.0` though
- Some feature requests are now easier/possible to implement with these new features
### New features
- Added `FS_NOTIFY_ERRORS` flag to display notifications for FS errors (#282)
- Added a `${workingDirectory}` variable that gets replaced during terminal creation (#323)

@ -1,4 +1,5 @@
import type { ConnectConfig } from 'ssh2';
import './ssh2';
export interface ProxyConfig {
type: 'socks4' | 'socks5' | 'http';

File diff suppressed because it is too large Load Diff

@ -411,7 +411,6 @@
"@types/node": "^12.7.12",
"@types/request": "^2.48.1",
"@types/semver": "^7.3.9",
"@types/ssh2": "^0.5.41",
"@types/vscode": "~1.49.0",
"@types/webpack": "^4.4.25",
"@types/winreg": "^1.2.30",
@ -429,12 +428,11 @@
"jsonc-parser": "^2.0.0",
"semver": "^7.3.5",
"socks": "^2.2.0",
"ssh2": "^0.8.9",
"ssh2-streams": "^0.4.10",
"ssh2": "^1.6.0",
"winreg": "^1.2.4"
},
"resolutions": {
"ssh2-streams": "Timmmm/ssh2-streams#patch-1"
"cpu-features": "npm:@favware/skip-dependency@1.1.3"
},
"workspaces": [
"./common",

@ -2,18 +2,14 @@ import type { FileSystemConfig } from 'common/fileSystemConfig';
import { readFile } from 'fs';
import { Socket } from 'net';
import { userInfo } from 'os';
import { Client, ClientChannel, ConnectConfig, SFTPWrapper as SFTPWrapperReal } from 'ssh2';
import { SFTPStream } from 'ssh2-streams';
import { Client, ClientChannel, ConnectConfig } from 'ssh2';
import { SFTP } from 'ssh2/lib/protocol/SFTP';
import * as vscode from 'vscode';
import { getConfig, getFlagBoolean } from './config';
import { Logging } from './logging';
import type { PuttySession } from './putty';
import { toPromise, validatePort } from './utils';
// tslint:disable-next-line:variable-name
const SFTPWrapper = require('ssh2/lib/SFTPWrapper') as (new (stream: SFTPStream) => SFTPWrapperReal);
type SFTPWrapper = SFTPWrapperReal;
const DEFAULT_CONFIG: ConnectConfig = {
tryKeyboard: true,
keepaliveInterval: 30e3,
@ -203,7 +199,7 @@ export async function createSocket(config: FileSystemConfig): Promise<NodeJS.Rea
logging.debug`\tGot no channel when connecting to hop ${config.hop} for ${config.name}`;
return reject(err);
}
channel.once('close', () => ssh.destroy());
channel.once('close', () => ssh.end());
resolve(channel);
});
});
@ -266,10 +262,19 @@ export async function createSSH(config: FileSystemConfig, sock?: NodeJS.Readable
const [flagV, flagR] = getFlagBoolean('DF-GE', false, config.flags);
if (flagV) {
logging.info`Flag "DF-GE" enabled due to '${flagR}', disabling DiffieHellman kex groupex algorithms`;
let kex: string[] = require('ssh2-streams/lib/constants').ALGORITHMS.KEX;
kex = kex.filter(algo => !algo.includes('diffie-hellman-group-exchange'));
logging.debug`\tResulting algorithms.kex: ${kex}`;
finalConfig.algorithms = { ...finalConfig.algorithms, kex };
const removeKex = finalConfig.algorithms?.kex;
if (removeKex) logging.debug`\tAlready present algorithms.kex: ${removeKex}`;
finalConfig.algorithms = {
...finalConfig.algorithms,
kex: {
...finalConfig.algorithms?.kex,
remove: [
...(Array.isArray(removeKex) ? removeKex : []),
'diffie-hellman-group-exchange',
],
},
};
logging.debug`\tResulting algorithms.kex: ${finalConfig.algorithms.kex}`;
}
client.connect(finalConfig);
} catch (e) {
@ -305,11 +310,11 @@ function startSudo(shell: ClientChannel, config: FileSystemConfig, user: string
return cleanup(), reject(new Error(`Sudo error: ${data}`));
}
function cleanup() {
shell.stdout.removeListener('data', stdout);
shell.stderr.removeListener('data', stderr);
shell.removeListener('data', stdout);
shell.stderr!.removeListener('data', stderr);
}
shell.stdout.on('data', stdout);
shell.stderr.on('data', stderr);
shell.on('data', stdout);
shell.stderr!.on('data', stderr);
const uFlag = typeof user === 'string' ? `-u ${user} ` : '';
shell.write(`sudo -S ${uFlag}bash -c "echo SUDO OK; cat | bash"\n`);
});
@ -333,7 +338,7 @@ function stripSudo(cmd: string) {
return cmd;
}
export async function getSFTP(client: Client, config: FileSystemConfig): Promise<SFTPWrapper> {
export async function getSFTP(client: Client, config: FileSystemConfig): Promise<SFTP> {
config = (await calculateActualConfig(config))!;
if (!config) throw new Error('Couldn\'t calculate the config');
const logging = Logging.scope(`getSFTP(${config.name})`);
@ -343,7 +348,7 @@ export async function getSFTP(client: Client, config: FileSystemConfig): Promise
}
if (!config.sftpCommand) {
logging.info`Creating SFTP session using standard sftp subsystem`;
return toPromise<SFTPWrapper>(cb => client.sftp(cb));
return toPromise<SFTP>(cb => client.sftp(cb));
}
let cmd = config.sftpCommand;
logging.info`Creating SFTP session using specified command: ${cmd}`;
@ -368,16 +373,17 @@ export async function getSFTP(client: Client, config: FileSystemConfig): Promise
await new Promise<void>((ready, nvm) => {
const handler = (data: string | Buffer) => {
if (data.toString().trim() !== 'SFTP READY') return;
shell.stdout.removeListener('data', handler);
shell.removeListener('data', handler);
ready();
};
shell.stdout.on('data', handler);
shell.on('data', handler);
shell.on('close', nvm);
});
// Start sftpCommand (e.g. /usr/lib/openssh/sftp-server) and wrap everything nicely
const sftps = new SFTPStream({ debug: config.debug });
shell.pipe(sftps).pipe(shell);
const sftp = new SFTPWrapper(sftps);
const sftp = new SFTP(client, shell, { debug: config.debug });
shell.on('data', data => sftp.push(data));
shell.on('close', data => data.end());
await toPromise(cb => shell.write(`${cmd}\n`, cb));
sftp._init();
return sftp;
}

@ -56,8 +56,8 @@ export class ConnectionManager {
shell.write(`echo ${shellConfig.embedSubstitutions`::sshfs:${'echo TTY'}:${'tty'}`}\n`);
return new Promise((resolvePath, rejectPath) => {
setTimeout(() => rejectPath(new Error('Timeout fetching command path')), 10e3);
const rl = readline.createInterface(shell.stdout);
shell.stdout.once('error', rejectPath);
const rl = readline.createInterface(shell);
shell.once('error', rejectPath);
shell.once('close', () => rejectPath());
rl.on('line', async line => {
if (debugLogging) logging.debug('<< ' + line);
@ -202,7 +202,7 @@ export class ConnectionManager {
this.connections.splice(index, 1);
clearInterval(connection.idleTimer);
this.onConnectionRemovedEmitter.fire(connection);
connection.client.destroy();
connection.client.end();
}
// Without making createConnection return a Proxy, or making Connection a class with
// getters and setters informing the manager that created it, we don't know if it updated.

@ -8,7 +8,7 @@ import { Logging, LOGGING_NO_STACKTRACE } from "./logging";
import { environmentToExportString, joinCommands, mergeEnvironment, toPromise } from './utils';
const [HEIGHT, WIDTH] = [480, 640];
const PSEUDO_TTY_OPTIONS: PseudoTtyOptions = {
const PSEUDO_TTY_OPTIONS: Partial<PseudoTtyOptions> = {
height: HEIGHT, width: WIDTH, term: 'xterm-256color',
};
@ -154,8 +154,8 @@ export async function createTerminal(options: TerminalOptions): Promise<SSHPseud
if (status === 'closed') return;
if (channel) {
pseudo.status = 'closed';
channel.signal('INT');
channel.signal('SIGINT');
channel.signal!('INT');
channel.signal!('SIGINT');
channel.write('\x03');
channel.close();
pseudo.channel = undefined;
@ -211,7 +211,7 @@ export async function createTerminal(options: TerminalOptions): Promise<SSHPseud
} else {
cmd = cmd.replace(/\${workingDirectory}/g, '');
}
const pseudoTtyOptions: PseudoTtyOptions = { ...PSEUDO_TTY_OPTIONS, cols: dims?.columns, rows: dims?.rows };
const pseudoTtyOptions: Partial<PseudoTtyOptions> = { ...PSEUDO_TTY_OPTIONS, cols: dims?.columns, rows: dims?.rows };
Logging.debug(`Starting shell for ${connection.actualConfig.name}: ${cmd}`);
const channel = await toPromise<ClientChannel | undefined>(cb => client.exec(cmd, { pty: pseudoTtyOptions }, cb));
if (!channel) throw new Error('Could not create remote terminal');
@ -236,8 +236,8 @@ export async function createTerminal(options: TerminalOptions): Promise<SSHPseud
if (pseudo.status === 'opening') pseudo.status = 'open';
onDidOpen.fire();
});
channel.stdout.on('data', chunk => onDidWrite.fire(chunk.toString()));
channel.stderr.on('data', chunk => onDidWrite.fire(chunk.toString()));
channel.on('data', chunk => onDidWrite.fire(chunk.toString()));
channel.stderr!.on('data', chunk => onDidWrite.fire(chunk.toString()));
// TODO: ^ Keep track of stdout's color, switch to red, output, then switch back?
} catch (e) {
Logging.error`Error starting SSH terminal:\n${e}`;
@ -255,7 +255,7 @@ export async function createTerminal(options: TerminalOptions): Promise<SSHPseud
terminal = term;
},
setDimensions(dims) {
pseudo.channel?.setWindow(dims.rows, dims.columns, HEIGHT, WIDTH);
pseudo.channel?.setWindow!(dims.rows, dims.columns, HEIGHT, WIDTH);
},
handleInput(data) {
if (pseudo.status === 'wait-to-close') return pseudo.close();

@ -1,5 +1,5 @@
import { posix as path } from 'path';
import type { Client, ClientChannel, SFTPWrapper } from "ssh2";
import type { Client, ClientChannel, SFTP } from "ssh2";
import type { Connection } from './connection';
import { Logger, Logging } from "./logging";
import { toPromise } from "./utils";
@ -24,12 +24,12 @@ type RemoteCommandInitializer = (connection: Connection) => void
| string | string[] | undefined
| Promise<void | string | string[] | undefined>;
async function ensureCachedFile(connection: Connection, key: string, path: string, content: string, sftp?: SFTPWrapper):
async function ensureCachedFile(connection: Connection, key: string, path: string, content: string, sftp?: SFTP):
Promise<[written: boolean, path: string | null]> {
const rc_files: Record<string, string> = connection.cache.rc_files ||= {};
if (rc_files[key]) return [false, rc_files[key]];
try {
sftp ||= await toPromise<SFTPWrapper>(cb => connection.client.sftp(cb));
sftp ||= await toPromise<SFTP>(cb => connection.client.sftp(cb));
await toPromise(cb => sftp!.writeFile(path, content, { mode: 0o755 }, cb));
return [true, rc_files[key] = path];
} catch (e) {
@ -40,7 +40,7 @@ async function ensureCachedFile(connection: Connection, key: string, path: strin
async function rcInitializePATH(connection: Connection): Promise<string[] | string> {
const dir = `/tmp/.Kelvin_sshfs.RcBin.${connection.actualConfig.username || Date.now()}`;
const sftp = await toPromise<SFTPWrapper>(cb => connection.client.sftp(cb));
const sftp = await toPromise<SFTP>(cb => connection.client.sftp(cb));
await toPromise(cb => sftp!.mkdir(dir, { mode: 0o755 }, cb)).catch(() => { });
const [, path] = await ensureCachedFile(connection, 'CmdCode', `${dir}/code`, SCRIPT_COMMAND_CODE, sftp);
return path ? [
@ -86,8 +86,8 @@ const KNOWN_SHELL_CONFIGS: Record<string, ShellConfig> = {}; {
export async function tryCommand(ssh: Client, command: string): Promise<string | null> {
const exec = await toPromise<ClientChannel>(cb => ssh.exec(command, cb));
const output = ['', ''] as [string, string];
exec.stdout.on('data', (chunk: any) => output[0] += chunk);
exec.stderr.on('data', (chunk: any) => output[1] += chunk);
exec.on('data', (chunk: any) => output[0] += chunk);
exec.stderr!.on('data', (chunk: any) => output[1] += chunk);
await toPromise(cb => {
exec.once('error', cb);
exec.once('close', cb);

@ -2,10 +2,10 @@
import type { FileSystemConfig } from 'common/fileSystemConfig';
import * as path from 'path';
import type * as ssh2 from 'ssh2';
import type * as ssh2s from 'ssh2-streams';
import * as vscode from 'vscode';
import { getFlagBoolean } from './config';
import { Logger, Logging, LOGGING_NO_STACKTRACE, LOGGING_SINGLE_LINE_STACKTRACE, withStacktraceOffset } from './logging';
import { toPromise } from './utils';
// This makes it report a single line of the stacktrace of where the e.g. logger.info() call happened
// while also making it that if we're logging an error, only the first 4 lines of the stack (including the error message) are shown
@ -36,14 +36,13 @@ function shouldIgnoreNotFound(target: string) {
export class SSHFileSystem implements vscode.FileSystemProvider {
protected onCloseEmitter = new vscode.EventEmitter<void>();
protected onDidChangeFileEmitter = new vscode.EventEmitter<vscode.FileChangeEvent[]>();
public waitForContinue = false;
public closed = false;
public closing = false;
public copy = undefined;
public onClose = this.onCloseEmitter.event;
public onDidChangeFile = this.onDidChangeFileEmitter.event;
protected logging: Logger;
constructor(public readonly authority: string, protected sftp: ssh2.SFTPWrapper, public readonly config: FileSystemConfig) {
constructor(public readonly authority: string, protected sftp: ssh2.SFTP, public readonly config: FileSystemConfig) {
this.logging = Logging.scope(`SSHFileSystem(${authority})`, false);
this.sftp.on('end', () => (this.closed = true, this.onCloseEmitter.fire()));
this.logging.info('SSHFileSystem created');
@ -52,34 +51,15 @@ export class SSHFileSystem implements vscode.FileSystemProvider {
this.closing = true;
this.sftp.end();
}
public continuePromise<T>(func: (cb: (err: Error | null | undefined, res?: T) => void) => boolean): Promise<T> {
return new Promise<T>((resolve, reject) => {
const exec = () => {
this.waitForContinue = false;
if (this.closed) return reject(new Error('Connection closed'));
try {
const canContinue = func((err, res) => err ? reject(err) : resolve(res!));
if (!canContinue) this.waitForContinue = true;
} catch (e) {
reject(e);
}
};
if (this.waitForContinue) {
this.sftp.once('continue', exec);
} else {
exec();
}
});
}
/* FileSystemProvider */
public watch(uri: vscode.Uri, options: { recursive: boolean; excludes: string[]; }): vscode.Disposable {
// throw new Error('Method not implemented.');
return new vscode.Disposable(() => { });
}
public async stat(uri: vscode.Uri): Promise<vscode.FileStat> {
const stat = await this.continuePromise<ssh2s.Stats>(cb => this.sftp.stat(uri.path, cb))
const stat = await toPromise<ssh2.sftp.Stats>(cb => this.sftp.stat(uri.path, cb))
.catch(e => this.handleError(uri, e, true) as never);
const { mtime, size } = stat;
const { mtime = 0, size = 0 } = stat;
let type = vscode.FileType.Unknown;
// tslint:disable no-bitwise */
if (stat.isFile()) type = type | vscode.FileType.File;
@ -92,14 +72,14 @@ export class SSHFileSystem implements vscode.FileSystemProvider {
};
}
public async readDirectory(uri: vscode.Uri): Promise<[string, vscode.FileType][]> {
const entries = await this.continuePromise<ssh2s.FileEntry[]>(cb => this.sftp.readdir(uri.path, cb))
const entries = await toPromise<ssh2.sftp.DirectoryEntry[]>(cb => this.sftp.readdir(uri.path, cb))
.catch((e) => this.handleError(uri, e, true) as never);
return Promise.all(entries.map(async (file) => {
const furi = uri.with({ path: `${uri.path}${uri.path.endsWith('/') ? '' : '/'}${file.filename}` });
// Mode in octal representation is 120XXX for links, e.g. 120777
// Any link's mode & 170000 should equal 120000 (using the octal system, at least)
// tslint:disable-next-line:no-bitwise
const link = (file.attrs.mode & 61440) === 40960 ? vscode.FileType.SymbolicLink : 0;
const link = (file.attrs.mode! & 61440) === 40960 ? vscode.FileType.SymbolicLink : 0;
try {
const type = (await this.stat(furi)).type;
// tslint:disable-next-line:no-bitwise
@ -112,7 +92,7 @@ export class SSHFileSystem implements vscode.FileSystemProvider {
}));
}
public createDirectory(uri: vscode.Uri): void | Promise<void> {
return this.continuePromise<void>(cb => this.sftp.mkdir(uri.path, cb)).catch(e => this.handleError(uri, e, true));
return toPromise<void>(cb => this.sftp.mkdir(uri.path, cb)).catch(e => this.handleError(uri, e, true));
}
public readFile(uri: vscode.Uri): Uint8Array | Promise<Uint8Array> {
return new Promise((resolve, reject) => {
@ -130,7 +110,7 @@ export class SSHFileSystem implements vscode.FileSystemProvider {
let mode: number | undefined;
let fileExists = false;
try {
const stat = await this.continuePromise<ssh2s.Stats>(cb => this.sftp.stat(uri.path, cb));
const stat = await toPromise<ssh2.sftp.Stats>(cb => this.sftp.stat(uri.path, cb));
mode = stat.mode;
fileExists = true;
} catch (e) {
@ -157,18 +137,18 @@ export class SSHFileSystem implements vscode.FileSystemProvider {
const fireEvent = () => this.onDidChangeFileEmitter.fire([{ uri, type: vscode.FileChangeType.Deleted }]);
// tslint:disable no-bitwise */
if (stats.type & (vscode.FileType.SymbolicLink | vscode.FileType.File)) {
return this.continuePromise(cb => this.sftp.unlink(uri.path, cb))
return toPromise(cb => this.sftp.unlink(uri.path, cb))
.then(fireEvent).catch(e => this.handleError(uri, e, true));
} else if ((stats.type & vscode.FileType.Directory) && options.recursive) {
return this.continuePromise(cb => this.sftp.rmdir(uri.path, cb))
return toPromise(cb => this.sftp.rmdir(uri.path, cb))
.then(fireEvent).catch(e => this.handleError(uri, e, true));
}
return this.continuePromise(cb => this.sftp.unlink(uri.path, cb))
return toPromise(cb => this.sftp.unlink(uri.path, cb))
.then(fireEvent).catch(e => this.handleError(uri, e, true));
// tslint:enable no-bitwise */
}
public rename(oldUri: vscode.Uri, newUri: vscode.Uri, options: { overwrite: boolean; }): void | Promise<void> {
return this.continuePromise<void>(cb => this.sftp.rename(oldUri.path, newUri.path, cb))
return toPromise<void>(cb => this.sftp.rename(oldUri.path, newUri.path, cb))
.then(() => this.onDidChangeFileEmitter.fire([
{ uri: oldUri, type: vscode.FileChangeType.Deleted },
{ uri: newUri, type: vscode.FileChangeType.Created }

@ -84,6 +84,9 @@ const config = {
plugins: [
new CopyPuttyExecutable(),
new WebpackPlugin(),
new webpack.IgnorePlugin({
resourceRegExp: /\.node$/,
}),
],
optimization: {
splitChunks: {

Loading…
Cancel
Save