Skip to content

Commit

Permalink
feat: better errors when IDL handler fails (#90)
Browse files Browse the repository at this point in the history
* feat: propagate IDL gen exit code and printing warning message if non-zero

* chore: printing handler error in red
  • Loading branch information
thlorenz authored Sep 23, 2022
1 parent 8b01df4 commit 8fd0058
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 20 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"@metaplex-foundation/beet-solana": "^0.3.1",
"@metaplex-foundation/rustbin": "^0.3.0",
"@solana/web3.js": "^1.56.2",
"ansi-colors": "^4.1.3",
"camelcase": "^6.2.1",
"debug": "^4.3.3",
"js-sha256": "^0.9.0",
Expand Down
62 changes: 46 additions & 16 deletions src/cli/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,22 @@ import {
ConfirmInstallArgs,
} from '@metaplex-foundation/rustbin'
import { spawn, SpawnOptionsWithoutStdio } from 'child_process'
import { SolitaConfig, SolitaConfigAnchor, SolitaConfigShank } from './types'
import {
SolitaConfig,
SolitaConfigAnchor,
SolitaConfigShank,
SolitaHandlerResult,
} from './types'
import path from 'path'
import { enhanceIdl } from './enhance-idl'
import { generateTypeScriptSDK } from './gen-typescript'
import { logError, logInfo } from '../utils'
import { logDebug, logError, logInfo } from '../utils'
import { Options as PrettierOptions } from 'prettier'

import { red } from 'ansi-colors'

const handlerErrorRx = /^Error\:/

export function handleAnchor(
config: SolitaConfigAnchor,
prettierConfig?: PrettierOptions
Expand Down Expand Up @@ -89,28 +98,49 @@ async function handle(
)
}

return new Promise<void>((resolve, reject) => {
return new Promise<SolitaHandlerResult>((resolve, reject) => {
const tool = path.basename(fullPathToBinary)
const idlGenerator = spawn(fullPathToBinary, spawnArgs, spawnOpts)
.on('error', (err) => {
logError(`${programName} idl generation failed`)
reject(err)
})
.on('exit', async () => {
logInfo('IDL written to: %s', path.join(idlDir, `${programName}.json`))
const idl = await enhanceIdl(config, binVersion, libVersion)
await generateTypeScriptSDK(
idl,
sdkDir,
prettierConfig,
config.typeAliases,
config.serializers,
anchorRemainingAccounts
)
resolve()
.on('exit', async (exitCode) => {
exitCode ??= 0

logDebug(`${tool} completed with code ${exitCode}`)
if (exitCode == 0) {
logInfo(
'IDL written to: %s',
path.join(idlDir, `${programName}.json`)
)
const idl = await enhanceIdl(config, binVersion, libVersion)
await generateTypeScriptSDK(
idl,
sdkDir,
prettierConfig,
config.typeAliases,
config.serializers,
anchorRemainingAccounts
)
resolve({ exitCode })
} else {
const errorMsg = red(
`${tool} returned with non-zero exit code. Please review the output above to diagnose the issue.`
)
resolve({ exitCode, errorMsg })
}
})

idlGenerator.stdout.on('data', (buf) => process.stdout.write(buf))
idlGenerator.stderr.on('data', (buf) => process.stderr.write(buf))
idlGenerator.stderr.on('data', (buf) => {
const dataStr = buf.toString()
if (handlerErrorRx.test(dataStr)) {
logError(red(dataStr))
} else {
process.stderr.write(buf)
}
})
})
}

Expand Down
29 changes: 25 additions & 4 deletions src/cli/solita.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@
import path from 'path'
import fs from 'fs'
import { canAccess, logDebug, logError, logInfo } from '../utils'
import { isSolitaConfigAnchor, isSolitaConfigShank } from './types'
import {
isErrorResult,
isSolitaConfigAnchor,
isSolitaConfigShank,
SolitaHandlerResult,
} from './types'
import { handleAnchor, handleShank } from './handlers'
import { strict as assert } from 'assert'

enum Loader {
JSON,
Expand Down Expand Up @@ -43,13 +49,28 @@ async function main() {
`Found '${prettierRes.rcFile}' in current directory and using that to format code`
)
}
let handlerResult: SolitaHandlerResult | undefined
if (isSolitaConfigAnchor(solitaConfig)) {
await handleAnchor(solitaConfig, prettierConfig)
handlerResult = await handleAnchor(solitaConfig, prettierConfig)
}
if (isSolitaConfigShank(solitaConfig)) {
await handleShank(solitaConfig, prettierConfig)
handlerResult = await handleShank(solitaConfig, prettierConfig)
}
assert(
handlerResult != null,
`IDL generator ${solitaConfig.idlGenerator} is not supported`
)

if (isErrorResult(handlerResult)) {
logError(handlerResult.errorMsg)
assert(
handlerResult.exitCode != 0,
'Handler exit code should be non-zero if an error was encountered'
)
process.exit(handlerResult.exitCode)
} else {
logInfo('Success!')
}
logInfo('Success!')
}

main()
Expand Down
8 changes: 8 additions & 0 deletions src/cli/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export type SolitaConfigShank = SolitaConfigBase & {

export type SolitaConfig = SolitaConfigAnchor | SolitaConfigShank

export type SolitaHandlerResult = { exitCode: number; errorMsg?: string }

// -----------------
// Guards
// -----------------
Expand All @@ -40,3 +42,9 @@ export function isSolitaConfigShank(
): config is SolitaConfigShank {
return config.idlGenerator === 'shank'
}

export function isErrorResult(
result: SolitaHandlerResult
): result is SolitaHandlerResult & { errorMsg: string } {
return result.errorMsg != null
}

0 comments on commit 8fd0058

Please sign in to comment.