Make use of improved logger with template literal support

issue/311
Kelvin Schoofs 3 years ago
parent 3e8aa832f5
commit bd25e7322d

@ -40,7 +40,7 @@ export async function renameNameless() {
}
});
if (okay) return;
return conf.update('configs', v, loc).then(() => { }, res => logging.error(`Error while saving configs (CT=${loc}): ${res}`));
return conf.update('configs', v, loc).then(() => { }, res => logging.error`Error while saving configs (CT=${loc}): ${res}`);
}
await patch(inspect.globalValue, vscode.ConfigurationTarget.Global);
await patch(inspect.workspaceValue, vscode.ConfigurationTarget.Workspace);
@ -58,18 +58,18 @@ async function readConfigFile(location: string, shouldExist = false): Promise<Fi
const content = await toPromise<Buffer>(cb => readFile(location, cb)).catch((e: NodeJS.ErrnoException) => e);
if (content instanceof Error) {
if (content.code === 'ENOENT' && !shouldExist) return [];
logging.error(`Error while reading config file ${location}: ${content.message}`);
logging.error`Error while reading config file ${location}: ${content}`;
return [];
}
const errors: ParseError[] = [];
const parsed: FileSystemConfig[] | null = parseJsonc(content.toString(), errors);
if (!parsed || errors.length) {
logging.error(`Couldn't parse ${location} as a 'JSON with Comments' file`);
logging.error`Couldn't parse ${location} as a 'JSON with Comments' file`;
vscode.window.showErrorMessage(`Couldn't parse ${location} as a 'JSON with Comments' file`);
return [];
}
parsed.forEach(c => c._locations = [c._location = location]);
logging.debug(`Read ${parsed.length} configs from ${location}`);
logging.debug`Read ${parsed.length} configs from ${location}`;
return parsed;
}
@ -132,7 +132,7 @@ export async function loadConfigsRaw(): Promise<FileSystemConfig[]> {
const fConfig = vscode.workspace.getConfiguration('sshfs', uri).inspect<FileSystemConfig[]>('configs');
const fConfigs = fConfig && fConfig.workspaceFolderValue || [];
if (fConfigs.length) {
logging.debug(`Read ${fConfigs.length} configs from workspace folder ${uri}`);
logging.debug`Read ${fConfigs.length} configs from workspace folder ${uri}`;
fConfigs.forEach(c => c._locations = [c._location = `WorkspaceFolder ${uri}`]);
}
layered.folder = [
@ -149,7 +149,7 @@ export async function loadConfigsRaw(): Promise<FileSystemConfig[]> {
// Let the user do some cleaning with the raw configs
for (const conf of all) {
if (!conf.name) {
logging.error(`Skipped an invalid SSH FS config (missing a name field):\n${JSON.stringify(conf, undefined, 4)}`);
logging.error`Skipped an invalid SSH FS config (missing a name field):\n${conf}`;
vscode.window.showErrorMessage(`Skipped an invalid SSH FS config (missing a name field)`);
} else if (invalidConfigName(conf.name)) {
logging.warning(`Found a SSH FS config with the invalid name "${conf.name}", prompting user how to handle`);
@ -158,14 +158,14 @@ export async function loadConfigsRaw(): Promise<FileSystemConfig[]> {
const name = await vscode.window.showInputBox({ prompt: `New name for: ${conf.name}`, validateInput: invalidConfigName, placeHolder: 'New name' });
if (name) {
const oldName = conf.name;
logging.info(`Renaming config "${oldName}" to "${name}"`);
logging.info`Renaming config "${oldName}" to "${name}"`;
conf.name = name;
return updateConfig(conf, oldName);
}
} else if (answer === 'Delete') {
return deleteConfig(conf);
}
logging.warning(`Skipped SSH FS config '${conf.name}'`);
logging.warning`Skipped SSH FS config '${conf.name}'`;
vscode.window.showWarningMessage(`Skipped SSH FS config '${conf.name}'`);
});
}
@ -186,19 +186,19 @@ export async function loadConfigs(): Promise<FileSystemConfig[]> {
// The folder settings should overwrite the higher up defined settings
// Since .sshfs.json gets read after vscode settings, these can overwrite configs
// of the same level, which I guess is a nice feature?
logging.debug(`\tMerging duplicate ${conf.name} from ${conf._locations}`);
logging.debug`\tMerging duplicate ${conf.name} from ${conf._locations}`;
dup._locations = [...dup._locations, ...conf._locations];
Object.assign(dup, Object.assign(conf, dup));
} else {
logging.debug(`\tIgnoring duplicate ${conf.name} from ${conf._locations}`);
logging.debug`\tIgnoring duplicate ${conf.name} from ${conf._locations}`;
}
} else {
logging.debug(`\tAdded configuration ${conf.name} from ${conf._locations}`);
logging.debug`\tAdded configuration ${conf.name} from ${conf._locations}`;
configs.push(conf);
}
}
loadedConfigs = configs;
logging.info(`Found ${loadedConfigs.length} configurations`);
logging.info`Found ${loadedConfigs.length} configurations`;
UPDATE_LISTENERS.forEach(listener => listener(loadedConfigs));
return loadedConfigs;
}
@ -223,7 +223,7 @@ export async function alterConfigs(location: ConfigLocation, alterer: ConfigAlte
return newConfig;
});
await conf.update('configs', modified, location);
logging.debug(`\tUpdated configs in ${[, 'Global', 'Workspace', 'WorkspaceFolder'][location]} settings.json`);
logging.debug`\tUpdated configs in ${[, 'Global', 'Workspace', 'WorkspaceFolder'][location]} settings.json`;
return;
}
if (typeof location !== 'string') throw new Error(`Invalid _location field: ${location}`);
@ -240,10 +240,10 @@ export async function alterConfigs(location: ConfigLocation, alterer: ConfigAlte
const data = JSON.stringify(altered, null, 4);
await toPromise(cb => writeFile(location, data, cb))
.catch((e: NodeJS.ErrnoException) => {
logging.error(`Error while writing configs to ${location}: ${e.message}`);
logging.error`Error while writing configs to ${location}: ${e}`;
throw e;
});
logging.debug(`\tWritten modified configs to ${location}`);
logging.debug`\tWritten modified configs to ${location}`;
await loadConfigs();
}
@ -251,18 +251,18 @@ export async function updateConfig(config: FileSystemConfig, oldName = config.na
const { name, _location } = config;
if (!name) throw new Error(`The given config has no name field`);
if (!_location) throw new Error(`The given config has no _location field`);
logging.info(`Saving config ${name} to ${_location}`);
logging.info`Saving config ${name} to ${_location}`;
if (oldName !== config.name) {
logging.debug(`\tSaving ${name} will try to overwrite old config ${oldName}`);
logging.debug`\tSaving ${name} will try to overwrite old config ${oldName}`;
}
await alterConfigs(_location, (configs) => {
logging.debug(`\tConfig location '${_location}' has following configs: ${configs.map(c => c.name).join(', ')}`);
logging.debug`\tConfig location '${_location}' has following configs: ${configs.map(c => c.name).join(', ')}`;
const index = configs.findIndex(c => c.name ? c.name.toLowerCase() === oldName.toLowerCase() : false);
if (index === -1) {
logging.debug(`\tAdding the new config to the existing configs`);
logging.debug`\tAdding the new config to the existing configs`;
configs.push(config);
} else {
logging.debug(`\tOverwriting config '${configs[index].name}' at index ${index} with the new config`);
logging.debug`\tOverwriting config '${configs[index].name}' at index ${index} with the new config`;
configs[index] = config;
}
return configs;
@ -273,12 +273,12 @@ export async function deleteConfig(config: FileSystemConfig) {
const { name, _location } = config;
if (!name) throw new Error(`The given config has no name field`);
if (!_location) throw new Error(`The given config has no _location field`);
logging.info(`Deleting config ${name} in ${_location}`);
logging.info`Deleting config ${name} in ${_location}`;
await alterConfigs(_location, (configs) => {
logging.debug(`\tConfig location '${_location}' has following configs: ${configs.map(c => c.name).join(', ')}`);
logging.debug`\tConfig location '${_location}' has following configs: ${configs.map(c => c.name).join(', ')}`;
const index = configs.findIndex(c => c.name ? c.name.toLowerCase() === name.toLowerCase() : false);
if (index === -1) throw new Error(`Config '${name}' not found in ${_location}`);
logging.debug(`\tDeleting config '${configs[index].name}' at index ${index}`);
logging.debug`\tDeleting config '${configs[index].name}' at index ${index}`;
configs.splice(index, 1);
return configs;
});
@ -299,7 +299,7 @@ export function getConfig(input: string): FileSystemConfig | undefined {
// If we're using the instant connection string, the host name might be a config name
const existing = getConfigs().find(c => c.name.toLowerCase() === parsed.host!.toLowerCase());
if (existing) {
Logging.info(`getConfig('${input}') led to '${parsed.name}' which matches config '${existing.name}'`);
Logging.info`getConfig('${input}') led to '${parsed.name}' which matches config '${existing.name}'`;
// Take the existing config, but (more or less) override it with the values present in `parsed`
// `name` be the same as in `parsed`, meaning it can be reused with `getConfig` on window reload.
return {
@ -404,7 +404,7 @@ function calculateFlags(): Record<string, FlagCombo> {
applyList(config.globalValue, 'Global Settings');
applyList(config.workspaceValue, 'Workspace Settings');
applyList(config.workspaceFolderValue, 'WorkspaceFolder Settings');
Logging.info(`Calculated config flags: ${JSON.stringify(flags)}`);
Logging.info`Calculated config flags: ${flags}`;
return cachedFlags = flags;
}

@ -6,7 +6,7 @@ import { SFTPStream } from 'ssh2-streams';
import * as vscode from 'vscode';
import { getConfig, getFlagBoolean } from './config';
import type { FileSystemConfig } from './fileSystemConfig';
import { censorConfig, Logging } from './logging';
import { Logging } from './logging';
import type { PuttySession } from './putty';
import { toPromise, validatePort } from './utils';
@ -38,7 +38,7 @@ async function promptFields(config: FileSystemConfig, ...fields: (keyof FileSyst
for (const field of fields) {
const prompt = PROMPT_FIELDS[field];
if (!prompt) {
Logging.error(`Prompting unexpected field '${field}'`);
Logging.error`Prompting unexpected field '${field}'`;
continue;
}
const value = config[field];
@ -69,7 +69,7 @@ export async function calculateActualConfig(config: FileSystemConfig): Promise<F
config.port = port ? validatePort(port) : 22;
config.agent = replaceVariables(config.agent);
config.privateKeyPath = replaceVariables(config.privateKeyPath);
logging.info(`Calculating actual config`);
logging.info`Calculating actual config`;
if (config.instantConnection) {
// Created from an instant connection string, so enable PuTTY (in try mode)
config.putty = '<TRY>'; // Could just set it to `true` but... consistency?
@ -86,7 +86,7 @@ export async function calculateActualConfig(config: FileSystemConfig): Promise<F
if (tryPutty) {
// If we're trying to find one, we also check whether `config.host` represents the name of a PuTTY session
session = await getSession(config.host);
logging.info(`\ttryPutty is true, tried finding a config named '${config.host}' and found ${session ? `'${session.name}'` : 'no match'}`);
logging.info`\ttryPutty is true, tried finding a config named '${config.host}' and found ${session ? `'${session.name}'` : 'no match'}`;
}
if (!session) {
let nameOnly = true;
@ -129,11 +129,11 @@ export async function calculateActualConfig(config: FileSystemConfig): Promise<F
default:
throw new Error(`The requested PuTTY session uses an unsupported proxy method`);
}
logging.debug(`\tReading PuTTY configuration lead to the following configuration:\n${JSON.stringify(config, null, 4)}`);
logging.debug`\tReading PuTTY configuration lead to the following configuration:\n${JSON.stringify(config, null, 4)}`;
} else if (!tryPutty) {
throw new Error(`Couldn't find the requested PuTTY session`);
} else {
logging.debug(`\tConfig suggested finding a PuTTY configuration, did not find one`);
logging.debug`\tConfig suggested finding a PuTTY configuration, did not find one`;
}
}
// If the username is (still) `$USER` at this point, use the local user's username
@ -142,7 +142,7 @@ export async function calculateActualConfig(config: FileSystemConfig): Promise<F
try {
const key = await toPromise<Buffer>(cb => readFile(config.privateKeyPath!, cb));
config.privateKey = key;
logging.debug(`\tRead private key from ${config.privateKeyPath}`);
logging.debug`\tRead private key from ${config.privateKeyPath}`;
} catch (e) {
throw new Error(`Error while reading the keyfile at:\n${config.privateKeyPath}`);
}
@ -166,11 +166,11 @@ export async function calculateActualConfig(config: FileSystemConfig): Promise<F
delete config.passphrase;
}
if (config.agentForward && !config.agent) {
logging.debug(`\tNo agent while having agentForward, disabling agent forwarding`);
logging.debug`\tNo agent while having agentForward, disabling agent forwarding`;
config.agentForward = false;
}
if (!config.privateKey && !config.agent && !config.password) {
logging.debug(`\tNo privateKey, agent or password. Gonna prompt for password`);
logging.debug`\tNo privateKey, agent or password. Gonna prompt for password`;
config.password = true as any;
await promptFields(config, 'password');
}
@ -182,25 +182,25 @@ export async function createSocket(config: FileSystemConfig): Promise<NodeJS.Rea
config = (await calculateActualConfig(config))!;
if (!config) return null;
const logging = Logging.scope(`createSocket(${config.name})`);
logging.info(`Creating socket`);
logging.info`Creating socket`;
if (config.hop) {
logging.debug(`\tHopping through ${config.hop}`);
logging.debug`\tHopping through ${config.hop}`;
const hop = getConfig(config.hop);
if (!hop) throw new Error(`A SSH FS configuration with the name '${config.hop}' doesn't exist`);
const ssh = await createSSH(hop);
if (!ssh) {
logging.debug(`\tFailed in connecting to hop ${config.hop}`);
logging.debug`\tFailed in connecting to hop ${config.hop}`;
return null;
}
return new Promise<NodeJS.ReadableStream>((resolve, reject) => {
ssh.forwardOut('localhost', 0, config.host!, config.port || 22, (err, channel) => {
if (err) {
logging.debug(`\tError connecting to hop ${config.hop} for ${config.name}: ${err}`);
err.message = `Couldn't connect through the hop:\n${err.message}`;
logging.debug`\tError connecting to hop ${config.hop} for ${config.name}: ${err}`;
err.message = `Couldn't connect through the hop:\n${err}`;
return reject(err);
} else if (!channel) {
err = new Error('Did not receive a channel');
logging.debug(`\tGot no channel when connecting to hop ${config.hop} for ${config.name}`);
logging.debug`\tGot no channel when connecting to hop ${config.hop} for ${config.name}`;
return reject(err);
}
channel.once('close', () => ssh.destroy());
@ -221,7 +221,7 @@ export async function createSocket(config: FileSystemConfig): Promise<NodeJS.Rea
throw new Error(`Unknown proxy method`);
}
return new Promise<NodeJS.ReadableStream>((resolve, reject) => {
logging.debug(`Connecting to ${config.host}:${config.port || 22}`);
logging.debug`Connecting to ${config.host}:${config.port || 22}`;
const socket = new Socket();
socket.connect(config.port || 22, config.host!, () => resolve(socket as NodeJS.ReadableStream));
socket.once('error', reject);
@ -239,7 +239,7 @@ export async function createSSH(config: FileSystemConfig, sock?: NodeJS.Readable
client.once('ready', () => resolve(client));
client.once('timeout', () => reject(new Error(`Socket timed out while connecting SSH FS '${config.name}'`)));
client.on('keyboard-interactive', (name, instructions, lang, prompts, finish) => {
logging.debug(`Received keyboard-interactive request with prompts "${JSON.stringify(prompts)}"`);
logging.debug`Received keyboard-interactive request with prompts ${prompts}`;
Promise.all<string>(prompts.map(prompt =>
vscode.window.showInputBox({
password: true, // prompt.echo was false for me while testing password prompting
@ -250,9 +250,9 @@ export async function createSSH(config: FileSystemConfig, sock?: NodeJS.Readable
});
client.on('error', (error: Error & { description?: string }) => {
if (error.description) {
error.message = `${error.description}\n${error.message}`;
error.message = `${error.description}\n${error}`;
}
logging.error(`${error.message || error}`);
logging.error(error);
reject(error);
});
try {
@ -265,10 +265,10 @@ export async function createSSH(config: FileSystemConfig, sock?: NodeJS.Readable
// Note: If the config already specifies a custom `algorithms.key`, ignore it (trust the user?)
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`);
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}`);
logging.debug`\tResulting algorithms.kex: ${kex}`;
finalConfig.algorithms = { ...finalConfig.algorithms, kex };
}
client.connect(finalConfig);
@ -279,14 +279,14 @@ export async function createSSH(config: FileSystemConfig, sock?: NodeJS.Readable
}
function startSudo(shell: ClientChannel, config: FileSystemConfig, user: string | boolean = true): Promise<void> {
Logging.debug(`Turning shell into a sudo shell for ${typeof user === 'string' ? `'${user}'` : 'default sudo user'}`);
Logging.debug`Turning shell into a sudo shell for ${typeof user === 'string' ? `'${user}'` : 'default sudo user'}`;
return new Promise((resolve, reject) => {
function stdout(data: Buffer | string) {
data = data.toString();
if (data.trim() === 'SUDO OK') {
return cleanup(), resolve();
} else {
Logging.debug(`Unexpected STDOUT: ${data}`);
Logging.debug`Unexpected STDOUT: ${data}`;
}
}
async function stderr(data: Buffer | string) {
@ -342,14 +342,14 @@ export async function getSFTP(client: Client, config: FileSystemConfig): Promise
config.sftpCommand = '/usr/lib/openssh/sftp-server';
}
if (!config.sftpCommand) {
logging.info(`Creating SFTP session using standard sftp subsystem`);
logging.info`Creating SFTP session using standard sftp subsystem`;
return toPromise<SFTPWrapper>(cb => client.sftp(cb));
}
let cmd = config.sftpCommand;
logging.info(`Creating SFTP session using specified command: ${cmd}`);
logging.info`Creating SFTP session using specified command: ${cmd}`;
const shell = await toPromise<ClientChannel>(cb => client.shell(false, cb));
// shell.stdout.on('data', (d: string | Buffer) => logging.debug(`[SFTP-STDOUT] ${d}`));
// shell.stderr.on('data', (d: string | Buffer) => logging.debug(`[SFTP-STDERR] ${d}`));
// shell.stdout.on('data', (d: string | Buffer) => logging.debug`[SFTP-STDOUT] ${d}`);
// shell.stderr.on('data', (d: string | Buffer) => logging.debug`[SFTP-STDERR] ${d}`);
// Maybe the user hasn't specified `sftpSudo`, but did put `sudo` in `sftpCommand`
// I can't find a good way of differentiating welcome messages, SFTP traffic, sudo password prompts, ...
// so convert the `sftpCommand` to make use of `sftpSudo`, since that seems to work

@ -97,12 +97,12 @@ export class ConnectionManager {
case 'code':
let [pwd, target] = args.split(':::');
if (!pwd || !target) {
logging.error(`Malformed 'code' command args: ${args}`);
logging.error`Malformed 'code' command args: ${args}`;
return;
}
pwd = pwd.trim();
target = target.trim();
logging.info(`Received command to open '${target}' while in '${pwd}'`);
logging.info`Received command to open '${target}' while in '${pwd}'`;
const absolutePath = target.startsWith('/') ? target : path.join(pwd, target);
const uri = vscode.Uri.parse(`ssh://${authority}/${absolutePath}`);
try {
@ -133,14 +133,14 @@ export class ConnectionManager {
}
return;
default:
logging.error(`Unrecognized command ${cmd} with args: ${args}`);
logging.error`Unrecognized command ${cmd} with args: ${args}`;
}
});
})
}
protected async _createConnection(name: string, config?: FileSystemConfig): Promise<Connection> {
const logging = Logging.scope(`createConnection(${name},${config ? 'config' : 'undefined'})`);
logging.info(`Creating a new connection for '${name}'`);
logging.info`Creating a new connection for '${name}'`;
const { createSSH, calculateActualConfig } = await import('./connect');
// Query and calculate the actual config
config = config || (await loadConfigs()).find(c => c.name === name);
@ -150,7 +150,7 @@ export class ConnectionManager {
// Start the actual SSH connection
const client = await createSSH(actualConfig);
if (!client) throw new Error(`Could not create SSH session for '${name}'`);
logging.info(`Remote version: ${(client as any)._remoteVer || 'N/A'}`);
logging.info`Remote version: ${(client as any)._remoteVer || 'N/A'}`;
// Query home directory
let home = await tryGetHome(client).catch((e: Error) => e);
if (typeof home !== 'string') {
@ -175,7 +175,7 @@ export class ConnectionManager {
if (flagRCV) {
const [flagRCDV, flagRCDR] = getFlagBoolean('DEBUG_REMOTE_COMMANDS', false, actualConfig.flags);
const withDebugStr = flagRCDV ? ` with debug logging enabled by '${flagRCDR}'` : '';
logging.info(`Flag REMOTE_COMMANDS provided in '${flagRCR}', setting up command terminal${withDebugStr}`);
logging.info`Flag REMOTE_COMMANDS provided in '${flagRCR}', setting up command terminal${withDebugStr}`;
const cmdPath = await this._createCommandTerminal(client, name, flagRCDV);
environment.push({ key: 'KELVIN_SSHFS_CMD_PATH', value: cmdPath });
const sftp = await toPromise<SFTPWrapper>(cb => client.sftp(cb));
@ -221,7 +221,7 @@ export class ConnectionManager {
const index = this.connections.indexOf(connection);
if (index === -1) return;
reason = reason ? `'${reason}' as reason` : ' no reason given';
Logging.info(`Closing connection to '${connection.actualConfig.name}' with ${reason}`);
Logging.info`Closing connection to '${connection.actualConfig.name}' with ${reason}`;
this.connections.splice(index, 1);
clearInterval(connection.idleTimer);
this.onConnectionRemovedEmitter.fire(connection);

@ -27,7 +27,7 @@ interface CommandHandler {
}
export function activate(context: vscode.ExtensionContext) {
Logging.info(`Extension activated, version ${getVersion()}, mode ${context.extensionMode}`);
Logging.info`Extension activated, version ${getVersion()}, mode ${context.extensionMode}`;
setDebug(process.env.VSCODE_SSHFS_DEBUG?.toLowerCase() === 'true');
@ -39,7 +39,7 @@ export function activate(context: vscode.ExtensionContext) {
if (!previousVersion) {
Logging.info('No previous version detected. Fresh or pre-v1.21.0 installation?');
} else if (previousVersion !== getVersion()) {
Logging.info(`Previously used version ${previousVersion}, first run after install.`);
Logging.info`Previously used version ${previousVersion}, first run after install.`;
}
// Really too bad we *need* the ExtensionContext for relative resources

@ -33,19 +33,19 @@ export class FileSystemRouter implements vscode.FileSystemProvider {
return (await this.assertFs(uri)).createDirectory(uri);
}
public async readFile(uri: vscode.Uri): Promise<Uint8Array> {
Logging.debug(`Reading ${uri}`);
Logging.debug`Reading ${uri}`;
return (await this.assertFs(uri)).readFile(uri);
}
public async writeFile(uri: vscode.Uri, content: Uint8Array, options: { create: boolean; overwrite: boolean; }): Promise<void> {
Logging.debug(`Writing ${content.length} bytes to ${uri}`);
Logging.debug`Writing ${content.length} bytes to ${uri}`;
return (await this.assertFs(uri)).writeFile(uri, content, options);
}
public async delete(uri: vscode.Uri, options: { recursive: boolean; }): Promise<void> {
Logging.debug(`Deleting ${uri}`);
Logging.debug`Deleting ${uri}`;
return (await this.assertFs(uri)).delete(uri, options);
}
public async rename(oldUri: vscode.Uri, newUri: vscode.Uri, options: { overwrite: boolean; }): Promise<void> {
Logging.debug(`Renaming ${oldUri} to ${newUri}`);
Logging.debug`Renaming ${oldUri} to ${newUri}`;
const fs = await this.assertFs(oldUri);
if (fs !== (await this.assertFs(newUri))) throw new Error(`Can't rename between different SSH filesystems`);
return fs.rename(oldUri, newUri, options);

@ -105,7 +105,7 @@ class Logger {
protected formatValue(value: any, options: LoggingOptions): string {
if (typeof value === 'string') return value;
if (value instanceof Error && value.stack) {
// Format errors with stacktraces to display the JSON and the stacktrace if needed
// Format errors with stacktraces to display the JSON and the stacktrace if needed
let result = `${value.name}: ${value.message}`;
try {
const json = JSON.stringify(value);
@ -170,7 +170,7 @@ class Logger {
return result.logger.print(result.type, message, result.options)
} else if (Array.isArray(message)) {
return result.logger.printTemplate(result.type, message, args, result.options)
}
}
result.logger.error`Trying to log type ${type} with message=${message} and args=${args}`;
};
result.logger = this;

@ -60,7 +60,7 @@ export class Manager implements vscode.TaskProvider, vscode.TerminalLinkProvider
// Create the actual SFTP session (using the connection's actualConfig, otherwise it'll reprompt for passwords etc)
const sftp = await getSFTP(con.client, con.actualConfig);
const fs = new SSHFileSystem(name, sftp, con.actualConfig);
Logging.info(`Created SSHFileSystem for ${name}, reading root directory...`);
Logging.info`Created SSHFileSystem for ${name}, reading root directory...`;
this.connectionManager.update(con, con => con.filesystems.push(fs));
this.fileSystems.push(fs);
delete this.creatingFileSystems[name];
@ -96,8 +96,7 @@ export class Manager implements vscode.TaskProvider, vscode.TerminalLinkProvider
this.commandDisconnect(name);
throw e;
}
Logging.error(`Error while connecting to SSH FS ${name}:\n${e.message}`);
Logging.error(e);
Logging.error`Error while connecting to SSH FS ${name}:\n${e}`;
vscode.window.showErrorMessage(`Error while connecting to SSH FS ${name}:\n${e.message}`, 'Retry', 'Configure', 'Ignore').then((chosen) => {
delete this.creatingFileSystems[name];
if (chosen === 'Retry') {
@ -213,7 +212,7 @@ export class Manager implements vscode.TaskProvider, vscode.TerminalLinkProvider
}
/* Commands (stuff for e.g. context menu for ssh-configs tree) */
public async commandConnect(config: FileSystemConfig) {
Logging.info(`Command received to connect ${config.name}`);
Logging.info`Command received to connect ${config.name}`;
const folders = vscode.workspace.workspaceFolders!;
const folder = folders && folders.find(f => f.uri.scheme === 'ssh' && f.uri.authority === config.name);
if (folder) return vscode.commands.executeCommand('workbench.files.action.refreshFilesExplorer');
@ -229,7 +228,7 @@ export class Manager implements vscode.TaskProvider, vscode.TerminalLinkProvider
});
}
public commandDisconnect(target: string | Connection) {
Logging.info(`Command received to disconnect ${commandArgumentToName(target)}`);
Logging.info`Command received to disconnect ${commandArgumentToName(target)}`;
let cons: Connection[];
if (typeof target === 'object' && 'client' in target) {
cons = [target];
@ -256,11 +255,12 @@ export class Manager implements vscode.TaskProvider, vscode.TerminalLinkProvider
vscode.workspace.updateWorkspaceFolders(start, folders.length - start, ...left);
}
public async commandTerminal(target: FileSystemConfig | Connection, uri?: vscode.Uri) {
Logging.info(`Command received to open a terminal for ${commandArgumentToName(target)}${uri ? ` in ${uri}` : ''}`);
Logging.info`Command received to open a terminal for ${commandArgumentToName(target)}${uri ? ` in ${uri}` : ''}`;
const config = 'client' in target ? target.actualConfig : target;
try {
await this.createTerminal(config.label || config.name, target, uri);
} catch (e) {
Logging.error`Error while creating terminal:\n${e}`;
const choice = await vscode.window.showErrorMessage<vscode.MessageItem>(
`Couldn't start a terminal for ${config.name}: ${e.message || e}`,
{ title: 'Retry' }, { title: 'Ignore', isCloseAffordance: true });
@ -268,7 +268,7 @@ export class Manager implements vscode.TaskProvider, vscode.TerminalLinkProvider
}
}
public async commandConfigure(target: string | FileSystemConfig) {
Logging.info(`Command received to configure ${typeof target === 'string' ? target : target.name}`);
Logging.info`Command received to configure ${typeof target === 'string' ? target : target.name}`;
if (typeof target === 'object') {
if (!target._location && !target._locations.length) {
vscode.window.showErrorMessage('Cannot configure a config-less connection!');
@ -282,7 +282,7 @@ export class Manager implements vscode.TaskProvider, vscode.TerminalLinkProvider
configs = configs.filter(c => c.name === target);
if (configs.length === 0) {
vscode.window.showErrorMessage(`Found no matching configs for '${target}'`);
return Logging.error(`Unexpectedly found no matching configs for '${target}' in commandConfigure?`);
return Logging.error`Unexpectedly found no matching configs for '${target}' in commandConfigure?`;
}
const config = configs.length === 1 ? configs[0] : configs;
this.openSettings({ config, type: 'editconfig' });

@ -8,7 +8,7 @@ import { toPromise, validatePort } from './utils';
async function resolveHostname(hostname: string): Promise<string> {
return toPromise<string>(cb => dns.lookup(hostname, cb)).then((ip) => {
Logging.debug(`Resolved hostname "${hostname}" to: ${ip}`);
Logging.debug`Resolved hostname "${hostname}" to: ${ip}`;
return ip;
});
}
@ -22,7 +22,7 @@ function validateConfig(config: FileSystemConfig) {
}
export async function socks(config: FileSystemConfig): Promise<NodeJS.ReadableStream> {
Logging.info(`Creating socks proxy connection for ${config.name}`);
Logging.info`Creating socks proxy connection for ${config.name}`;
validateConfig(config);
if (config.proxy!.type !== 'socks4' && config.proxy!.type !== 'socks5') {
throw new Error(`Expected 'config.proxy.type' to be 'socks4' or 'socks5'`);
@ -30,7 +30,7 @@ export async function socks(config: FileSystemConfig): Promise<NodeJS.ReadableSt
try {
const ipaddress = (await resolveHostname(config.proxy!.host));
if (!ipaddress) throw new Error(`Couldn't resolve '${config.proxy!.host}'`);
Logging.debug(`\tConnecting to ${config.host}:${config.port} over ${config.proxy!.type} proxy at ${ipaddress}:${config.proxy!.port}`);
Logging.debug`\tConnecting to ${config.host}:${config.port} over ${config.proxy!.type} proxy at ${ipaddress}:${config.proxy!.port}`;
const con = await SocksClient.createConnection({
command: 'connect',
destination: {
@ -50,14 +50,14 @@ export async function socks(config: FileSystemConfig): Promise<NodeJS.ReadableSt
}
export function http(config: FileSystemConfig): Promise<NodeJS.ReadableStream> {
Logging.info(`Creating http proxy connection for ${config.name}`);
Logging.info`Creating http proxy connection for ${config.name}`;
validateConfig(config);
return new Promise<NodeJS.ReadableStream>((resolve, reject) => {
if (config.proxy!.type !== 'http') {
reject(new Error(`Expected config.proxy.type' to be 'http'`));
}
try {
Logging.debug(`\tConnecting to ${config.host}:${config.port} over http proxy at ${config.proxy!.host}:${config.proxy!.port}`);
Logging.debug`\tConnecting to ${config.host}:${config.port} over http proxy at ${config.proxy!.host}:${config.proxy!.port}`;
const req = request({
port: config.proxy!.port,
hostname: config.proxy!.host,

@ -49,7 +49,7 @@ export function formatSession(session: PuttySession): string {
}
export async function getSessions() {
Logging.info(`Fetching PuTTY sessions from registry`);
Logging.info`Fetching PuTTY sessions from registry`;
const values = await toPromise<Winreg.Registry[]>(cb => winreg.keys(cb));
const sessions: PuttySession[] = [];
await Promise.all(values.map(regSession => (async () => {
@ -59,8 +59,8 @@ export async function getSessions() {
props.forEach(prop => properties[prop.name.toLowerCase()] = valueFromItem(prop));
sessions.push({ name, ...(properties as any) });
})()));
Logging.debug(`\tFound ${sessions.length} sessions:`);
sessions.forEach(s => Logging.debug(`\t- ${formatSession(s)}`));
Logging.debug`\tFound ${sessions.length} sessions:`;
sessions.forEach(s => Logging.debug`\t- ${formatSession(s)}`);
return sessions;
}

@ -104,8 +104,7 @@ export class SSHFileSystem implements vscode.FileSystemProvider {
// tslint:disable-next-line:no-bitwise
return [file.filename, type | link] as [string, vscode.FileType];
} catch (e) {
this.logging.warning(`Error in readDirectory for ${furi}`, LOGGING_NO_STACKTRACE);
this.logging.warning(e, LOGGING_SINGLE_LINE_STACKTRACE);
this.logging.warning.withOptions(LOGGING_SINGLE_LINE_STACKTRACE)`Error in readDirectory for ${furi}: ${e}`;
// tslint:disable-next-line:no-bitwise
return [file.filename, vscode.FileType.Unknown | link] as [string, vscode.FileType];
}
@ -182,8 +181,7 @@ export class SSHFileSystem implements vscode.FileSystemProvider {
this.logging.debug(`Ignored FileNotFound error for: ${uri}`, LOGGING_NO_STACKTRACE);
if (doThrow === true) throw e; else if (doThrow) return doThrow(e); else return;
}
Logging.error(`Error handling uri: ${uri}`, LOGGING_NO_STACKTRACE);
Logging.error(e, LOGGING_HANDLE_ERROR);
Logging.error.withOptions(LOGGING_HANDLE_ERROR)`Error handling uri: ${uri}\n${e}`;
// Convert SSH2Stream error codes into VS Code errors
if (doThrow && typeof e.code === 'number') {
const oldE = e;

@ -67,7 +67,7 @@ export async function open() {
}
export async function navigate(navigation: Navigation) {
Logging.debug(`Navigation requested: ${JSON.stringify(navigation, null, 4)}`);
Logging.debug`Navigation requested: ${navigation}`;
pendingNavigation = navigation;
postMessage({ navigation, type: 'navigate' });
return open();
@ -78,8 +78,8 @@ function postMessage<T extends Message>(message: T) {
}
async function handleMessage(message: Message): Promise<any> {
if (!webviewPanel) return Logging.warning(`Got message without webviewPanel: ${JSON.stringify(message, null, 4)}`);
Logging.debug(`Got message: ${JSON.stringify(message, null, 4)}`);
if (!webviewPanel) return Logging.warning`Got message without webviewPanel: ${message}`;
Logging.debug`Got message: ${message}`;
if (pendingNavigation) {
postMessage({
type: 'navigate',
@ -124,9 +124,7 @@ async function handleMessage(message: Message): Promise<any> {
const uris = await vscode.window.showOpenDialog({});
if (uris) [uri] = uris;
} catch (e) {
Logging.error('Error handling promptPath message for settings UI:', LOGGING_NO_STACKTRACE);
Logging.error(JSON.stringify(message), LOGGING_NO_STACKTRACE);
Logging.error(e);
Logging.error`Error handling promptPath message for settings UI:\n${message}\n${e}`;
error = e.message;
}
return postMessage({

Loading…
Cancel
Save