diff --git a/packages/cli/src/commands/config/index.ts b/packages/cli/src/commands/config/index.ts index 80525ee47..d988e9ab7 100644 --- a/packages/cli/src/commands/config/index.ts +++ b/packages/cli/src/commands/config/index.ts @@ -581,6 +581,11 @@ export const commandsConfig: CommandsConfig = { flags: '-s --sources', description: 'Show contract sources', }, + { + flags: '--match-contract ', + description: 'Regex to filter contracts by name. Only matching contracts are shown/exported.', + defaultValue: '', + }, ...debugVerbosity, ], }, diff --git a/packages/cli/src/commands/inspect.ts b/packages/cli/src/commands/inspect.ts index c8fb14b67..cb84c8269 100644 --- a/packages/cli/src/commands/inspect.ts +++ b/packages/cli/src/commands/inspect.ts @@ -1,7 +1,9 @@ import { + BundledChainBuilderOutputs, ChainArtifacts, ChainDefinition, ContractData, + ContractMap, DeploymentInfo, DeploymentState, fetchIPFSAvailability, @@ -32,12 +34,18 @@ export async function inspect( cliSettings: CliSettings, out: FormatType, writeDeployments: string, - sources: boolean + sources: boolean, + matchContract = '' ) { if (out && !formatTypes.includes(out)) { throw new Error(`invalid --out value: "${out}". Valid types are: '${formatTypes.join("' | '")}'`); } + if (matchContract) { + const regex = new RegExp(matchContract); + deployInfo.state = _filterState(deployInfo.state, regex); + } + const resolver = await createDefaultReadRegistry(cliSettings); const loader = getMainLoader(cliSettings); @@ -79,7 +87,21 @@ export async function inspect( const packageOwner = deployInfo.def.setting?.owner?.defaultValue; const localSource = getSourceFromRegistry(resolver.registries); const ipfsAvailabilityScore = await fetchIPFSAvailability(cliSettings.ipfsUrl, ipfsUrl.replace('ipfs://', '')); - const contractsAndDetails = getContractsAndDetails(deployInfo.state); + let contractsAndDetails = getContractsAndDetails(deployInfo.state); + + if (matchContract) { + const regex = new RegExp(matchContract); + const stateContracts = _getNestedStateContracts(deployInfo.state); + const filtered: ContractMap = {}; + for (const [filepath, contractData] of stateContracts.entries()) { + const contractName = path.basename(filepath, '.json'); + if (regex.test(contractName)) { + filtered[contractName] = contractData; + } + } + contractsAndDetails = filtered; + } + const miscData = await loader.ipfs.read(deployInfo.miscUrl); const contractSources = _listSourceCodeContracts(miscData); @@ -164,6 +186,28 @@ function _getNestedStateFiles(artifacts: ChainArtifacts, pathname: string, resul return result; } +function _filterState(state: DeploymentState, regex: RegExp): DeploymentState { + return _.pickBy( + _.mapValues(state, (val) => ({ ...val, artifacts: _filterArtifacts(val.artifacts, regex) })), + (val) => Object.keys(val.artifacts.contracts || {}).length > 0 || Object.keys(val.artifacts.imports || {}).length > 0 + ); +} + +function _filterArtifacts(artifacts: ChainArtifacts, regex: RegExp): ChainArtifacts { + const newArtifacts: ChainArtifacts = { ...artifacts }; + if (newArtifacts.contracts) { + newArtifacts.contracts = _.pickBy(newArtifacts.contracts, (v, k) => regex.test(k)) as ContractMap; + } + if (newArtifacts.imports) { + const filteredImports = _.pickBy( + _.mapValues(newArtifacts.imports, (i) => _filterArtifacts(i, regex)), + (v) => Object.keys(v.contracts || {}).length > 0 || Object.keys(v.imports || {}).length > 0 + ) as BundledChainBuilderOutputs; + newArtifacts.imports = filteredImports; + } + return newArtifacts; +} + // TODO: types function _listSourceCodeContracts(miscData: any) { return Object.keys(_.pickBy(miscData.artifacts, (v) => v.source)); diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 763d1f058..71ecd1aec 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -653,7 +653,8 @@ applyCommandsConfig(program.command('inspect'), commandsConfig.inspect).action(a cliSettings, options.json ? 'deploy-json' : options.out, options.writeDeployments, - options.sources + options.sources, + options.matchContract ); logSpinnerEnd();