Skip to content

Commit 82b016f

Browse files
authored
refactor(util): tryRun() can take a regex #6640
## Problem This is aimed at fixing the following ec2 bug. Attempting to generate the ssh keys via tryRun can log a failure, when there is no failure. Looking at https://github.com/aws/aws-toolkit-vscode/blob/35502be238b1bf7c3ff73e44df8d077a6d32aa85/packages/core/src/awsService/ec2/sshKeyPair.ts#L78-L86 We use `tryRun` to detect if the output contains "unknown key type". This allows us to detect when a certain key type such as RSA or ed25519 is not supported on the local machine. Detecting if the key generated successfully is a harder problem, as the output did not contain a consistent message. However, it results in `tryRun` logging a failure to find "unknown key type" in the output, which means failed to find the expected text in the output, but still generated the key. This is then logged as a failure, but is functionally a success. This is very confusing behavior. The root of this problem is we are trying to use `tryRun` in a way it doesn't naturally support. Rather than use it awkwardly, we can extend it. ## Solution - add support for regex in tryRun New logs: ``` 2025-02-20 12:07:01.624 [info] tryRun: ok: PID 22605: [ssh-keygen -t ed25519 -N -q -f /Users/hkobew/Library/Application Support/Code/User/globalStorage/amazonwebservices.aws-toolkit-vscode/aws-ec2-key] { exitCode: 0, stdout: '/Users/hkobew/Library/Application Support/Code/User/globalStorage/amazonwebservices.aws-toolkit-vscode/aws-ec2-key already exists.\n' + 'Overwrite (y/n)?', stderr: '', error: undefined, signal: undefined } ```
1 parent 8d67f7a commit 82b016f

File tree

4 files changed

+38
-6
lines changed

4 files changed

+38
-6
lines changed

packages/core/src/awsService/ec2/sshKeyPair.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,16 @@ export class SshKeyPair {
7979
const overrideKeys = async (_t: string, proc: RunParameterContext) => {
8080
await proc.send('yes')
8181
}
82-
return !(await tryRun('ssh-keygen', ['-t', keyType, '-N', '', '-q', '-f', keyPath], 'yes', 'unknown key type', {
83-
onStdout: overrideKeys,
84-
timeout: new Timeout(5000),
85-
}))
82+
return await tryRun(
83+
'ssh-keygen',
84+
['-t', keyType, '-N', '', '-q', '-f', keyPath],
85+
'yes',
86+
/^(?!.*Unknown key type).*/i,
87+
{
88+
onStdout: overrideKeys,
89+
timeout: new Timeout(5000),
90+
}
91+
)
8692
}
8793

8894
public static async tryKeyTypes(keyPath: string, keyTypes: sshKeyType[]): Promise<boolean> {

packages/core/src/shared/utilities/pathFind.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { GitExtension } from '../extensions/git'
1111
import { Settings } from '../settings'
1212
import { getLogger } from '../logger/logger'
1313
import { mergeResolvedShellPath } from '../env/resolveEnv'
14+
import { matchesPattern } from './textUtilities'
1415

1516
/** Full path to VSCode CLI. */
1617
let vscPath: string
@@ -32,15 +33,15 @@ export async function tryRun(
3233
p: string,
3334
args: string[],
3435
logging: 'yes' | 'no' | 'noresult' = 'yes',
35-
expected?: string,
36+
expected?: string | RegExp,
3637
opt?: ChildProcessOptions
3738
): Promise<boolean> {
3839
const proc = new ChildProcess(p, args, { logging: 'no' })
3940
const r = await proc.run({
4041
...opt,
4142
spawnOptions: { env: await mergeResolvedShellPath(opt?.spawnOptions?.env ?? process.env) },
4243
})
43-
const ok = r.exitCode === 0 && (expected === undefined || r.stdout.includes(expected))
44+
const ok = r.exitCode === 0 && (expected === undefined || matchesPattern(r.stdout, expected))
4445
if (logging === 'noresult') {
4546
getLogger().info('tryRun: %s: %s', ok ? 'ok' : 'failed', proc)
4647
} else if (logging !== 'no') {

packages/core/src/shared/utilities/textUtilities.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,3 +273,10 @@ export function extractFileAndCodeSelectionFromMessage(message: any) {
273273
const selection = message?.context?.focusAreaContext?.selectionInsideExtendedCodeBlock as vscode.Selection
274274
return { filePath, selection }
275275
}
276+
277+
export function matchesPattern(source: string, target: string | RegExp) {
278+
if (typeof target === 'string') {
279+
return source.includes(target)
280+
}
281+
return target.test(source)
282+
}

packages/core/src/test/shared/utilities/pathFind.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,24 @@ describe('pathFind', function () {
4242
assert.ok(regex.test(vscPath), `expected regex ${regex} to match: "${vscPath}"`)
4343
})
4444

45+
describe('tryRun', function () {
46+
it('returns true if output matches expected', async function () {
47+
const posResult = await tryRun('echo', ['hello'], 'no', 'hello')
48+
assert.ok(posResult)
49+
50+
const negResult = await tryRun('echo', ['hi'], 'no', 'hello')
51+
assert.ok(!negResult)
52+
})
53+
54+
it('supports regex on output match', async function () {
55+
const posResult = await tryRun('echo', ['hello'], 'no', /hel*o/)
56+
assert.ok(posResult)
57+
58+
const negResult = await tryRun('echo', ['hi'], 'no', /^(?!(hi)).*$/)
59+
assert.ok(!negResult)
60+
})
61+
})
62+
4563
describe('findSshPath', function () {
4664
let previousPath: string | undefined
4765

0 commit comments

Comments
 (0)