-
-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move flag system to separate file and fix import quotes
- Loading branch information
1 parent
5721f1c
commit 11b8f05
Showing
12 changed files
with
201 additions
and
181 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
import * as semver from 'semver'; | ||
import * as vscode from 'vscode'; | ||
import { Logging } from './logging'; | ||
import { catchingPromise } from './utils'; | ||
|
||
/* List of flags | ||
DF-GE (boolean) (default=false) | ||
- Disables the 'diffie-hellman-group-exchange' kex algorithm as a default option | ||
- Originally for issue #239 | ||
- Automatically enabled for Electron v11.0, v11.1 and v11.2 | ||
DEBUG_SSH2 (boolean) (default=false) | ||
- Enables debug logging in the ssh2 library (set at the start of each connection) | ||
WINDOWS_COMMAND_SEPARATOR (boolean) (default=false) | ||
- Makes it that commands are joined together using ` && ` instead of `; ` | ||
- Automatically enabled when the remote shell is detected to be PowerShell or Command Prompt (cmd.exe) | ||
CHECK_HOME (boolean) (default=true) | ||
- Determines whether we check if the home directory exists during `createFileSystem` in the Manager | ||
- If `tryGetHome` fails while creating the connection, throw an error if this flag is set, otherwise default to `/` | ||
REMOTE_COMMANDS (boolean) (default=false) | ||
- Enables automatically launching a background command terminal during connection setup | ||
- Enables attempting to inject a file to be sourced by the remote shells (which adds the `code` alias) | ||
DEBUG_REMOTE_COMMANDS (boolean) (default=false) | ||
- Enables debug logging for the remote command terminal (thus useless if REMOTE_COMMANDS isn't true) | ||
DEBUG_FS (string) (default='') | ||
- A comma-separated list of debug flags for logging errors in the sshFileSystem | ||
- The presence of `showignored` will log `FileNotFound` that got ignored | ||
- The presence of `disableignored` will make the code ignore nothing (making `showignored` useless) | ||
- The presence of `minimal` will log all errors as single lines, but not `FileNotFound` | ||
- The presence of `full` is the same as `minimal` but with full stacktraces | ||
- The presence of `converted` will log the resulting converted errors (if required and successful) | ||
- The presence of `all` enables all of the above except `disableignored` (similar to `showignored,full,converted`) | ||
DEBUG_FSR (string) (default='', global) | ||
- A comma-separated list of method names to enable logging for in the FileSystemRouter | ||
- The presence of `all` is equal to `stat,readDirectory,createDirectory,readFile,writeFile,delete,rename` | ||
- The router logs handles `ssh://`, and will even log operations to non-existing configurations/connections | ||
FS_NOTIFY_ERRORS (string) (default='') | ||
- A comma-separated list of operations to display notifications for should they error | ||
- Mind that `FileNotFound` errors for ignored paths are always ignored, except with `DEBUG_FS=showignored` | ||
- The presence of `all` will show notification for every operation | ||
- The presence of `write` is equal to `createDirectory,writeFile,delete,rename` | ||
- Besides those provided by `write`, there's also `readDirectory`, `readFile` and `stat` | ||
- Automatically set to `write` for VS Code 1.56 and later (see issue #282) | ||
SHELL_CONFIG (string) | ||
- Forces the use of a specific shell configuration. Check shellConfig.ts for possible values | ||
- By default, when this flag is absent (or an empty or not a string), the extension will try to detect the correct type to use | ||
*/ | ||
|
||
function parseFlagList(list: string[] | undefined, origin: string): Record<string, FlagCombo> { | ||
if (list === undefined) | ||
return {}; | ||
if (!Array.isArray(list)) | ||
throw new Error(`Expected string array for flags, but got: ${list}`); | ||
const scope: Record<string, FlagCombo> = {}; | ||
for (const flag of list) { | ||
let name: string = flag; | ||
let value: FlagValue = null; | ||
const eq = flag.indexOf('='); | ||
if (eq !== -1) { | ||
name = flag.substring(0, eq); | ||
value = flag.substring(eq + 1); | ||
} else if (flag.startsWith('+')) { | ||
name = flag.substring(1); | ||
value = true; | ||
} else if (flag.startsWith('-')) { | ||
name = flag.substring(1); | ||
value = false; | ||
} | ||
name = name.toLocaleLowerCase(); | ||
if (name in scope) | ||
continue; | ||
scope[name] = [value, origin]; | ||
} | ||
return scope; | ||
} | ||
|
||
export type FlagValue = string | boolean | null; | ||
export type FlagCombo<V extends FlagValue = FlagValue> = [value: V, origin: string]; | ||
const globalFlagsSubscribers = new Set<() => void>(); | ||
export function subscribeToGlobalFlags(listener: () => void): vscode.Disposable { | ||
listener(); | ||
globalFlagsSubscribers.add(listener); | ||
return new vscode.Disposable(() => globalFlagsSubscribers.delete(listener)); | ||
} | ||
|
||
const DEFAULT_FLAGS: string[] = []; | ||
let cachedFlags: Record<string, FlagCombo> = {}; | ||
function calculateFlags(): Record<string, FlagCombo> { | ||
const flags: Record<string, FlagCombo> = {}; | ||
const config = vscode.workspace.getConfiguration('sshfs').inspect<string[]>('flags'); | ||
if (!config) | ||
throw new Error(`Could not inspect "sshfs.flags" config field`); | ||
const applyList = (list: string[] | undefined, origin: string) => Object.assign(flags, parseFlagList(list, origin)); | ||
applyList(DEFAULT_FLAGS, 'Built-in Default'); | ||
applyList(config.defaultValue, 'Default Settings'); | ||
// Electron v11 crashes for DiffieHellman GroupExchange, although it's fixed in 11.3.0 | ||
if ((process.versions as { electron?: string; }).electron?.match(/^11\.(0|1|2)\./)) { | ||
applyList(['+DF-GE'], 'Fix for issue #239'); | ||
} | ||
// Starting with 1.56, FileSystemProvider errors aren't shown to the user and just silently fail | ||
// https://github.com/SchoofsKelvin/vscode-sshfs/issues/282 | ||
if (semver.gte(vscode.version, '1.56.0')) { | ||
applyList(['+FS_NOTIFY_ERRORS'], 'Fix for issue #282'); | ||
} | ||
applyList(config.globalValue, 'Global Settings'); | ||
applyList(config.workspaceValue, 'Workspace Settings'); | ||
applyList(config.workspaceFolderValue, 'WorkspaceFolder Settings'); | ||
Logging.info`Calculated config flags: ${flags}`; | ||
for (const listener of globalFlagsSubscribers) { | ||
catchingPromise(listener).catch(e => Logging.error`onGlobalFlagsChanged listener errored: ${e}`); | ||
} | ||
return cachedFlags = flags; | ||
} | ||
vscode.workspace.onDidChangeConfiguration(event => { | ||
if (event.affectsConfiguration('sshfs.flags')) | ||
calculateFlags(); | ||
}); | ||
calculateFlags(); | ||
|
||
/** | ||
* Returns (a copy of the) global flags. Gets updated by ConfigurationChangeEvent events. | ||
* In case `flags` is given, flags specified in this array will override global ones in the returned result. | ||
* @param flags An optional array of flags to check before the global ones | ||
*/ | ||
function getFlags(flags?: string[]): Record<string, FlagCombo> { | ||
return { | ||
...cachedFlags, | ||
...parseFlagList(flags, 'Override'), | ||
}; | ||
} | ||
|
||
/** | ||
* Checks the `sshfs.flags` config (overridable by e.g. workspace settings). | ||
* - Flag names are case-insensitive | ||
* - If a flag appears twice, the first mention of it is used | ||
* - If a flag appears as "NAME", `null` is returned | ||
* - If a flag appears as "FLAG=VALUE", `VALUE` is returned as a string | ||
* - If a flag appears as `+FLAG` (and no `=`), `true` is returned (as a boolean) | ||
* - If a flag appears as `-FLAG` (and no `=`), `false` is returned (as a boolean) | ||
* - If a flag is missing, `undefined` is returned (different from `null`!) | ||
* | ||
* For `undefined`, an actual `undefined` is returned. For all other cases, a FlagCombo | ||
* is returned, e.g. "NAME" returns `[null, "someOrigin"]` and `"+F"` returns `[true, "someOrigin"]` | ||
* @param target The name of the flag to look for | ||
* @param flags An optional array of flags to check before the global ones | ||
*/ | ||
export function getFlag(target: string, flags?: string[]): FlagCombo | undefined { | ||
return getFlags(flags)[target.toLowerCase()]; | ||
} | ||
|
||
/** | ||
* Built on top of getFlag. Tries to convert the flag value to a boolean using these rules: | ||
* - If the flag isn't present, `missingValue` is returned | ||
* Although this probably means I'm using a flag that I never added to `DEFAULT_FLAGS` | ||
* - Booleans are kept | ||
* - `null` is counted as `true` (means a flag like "NAME" was present without any value or prefix) | ||
* - Strings try to get converted in a case-insensitive way: | ||
* - `true/t/yes/y` becomes true | ||
* - `false/f/no/n` becomes false | ||
* - All other strings result in an error | ||
* @param target The name of the flag to look for | ||
* @param defaultValue The value to return when no flag with the given name is present | ||
* @param flags An optional array of flags to check before the global ones | ||
* @returns The matching FlagCombo or `[missingValue, 'missing']` instead | ||
*/ | ||
export function getFlagBoolean(target: string, missingValue: boolean, flags?: string[]): FlagCombo<boolean> { | ||
const combo = getFlag(target, flags); | ||
if (!combo) | ||
return [missingValue, 'missing']; | ||
const [value, reason] = combo; | ||
if (value == null) | ||
return [true, reason]; | ||
if (typeof value === 'boolean') | ||
return [value, reason]; | ||
const lower = value.toLowerCase(); | ||
if (lower === 'true' || lower === 't' || lower === 'yes' || lower === 'y') | ||
return [true, reason]; | ||
if (lower === 'false' || lower === 'f' || lower === 'no' || lower === 'n') | ||
return [false, reason]; | ||
throw new Error(`Could not convert '${value}' for flag '${target}' to a boolean!`); | ||
} |
Oops, something went wrong.