import type { NoirPackageConfig } from '@aztec/foundation/noir'; import TOML from '@iarna/toml'; import { CommanderError } from 'commander'; import { rename, writeFile } from 'fs/promises'; /** * Updates a file in place atomically. * @param filePath - Path to file * @param contents - New contents to write */ export async function atomicUpdateFile(filePath: string, contents: string) { const tmpFilepath = filePath + '.tmp'; try { await writeFile(tmpFilepath, contents, { // let's crash if the tmp file already exists flag: 'wx', }); await rename(tmpFilepath, filePath); } catch (e) { if (e instanceof Error && 'code' in e && e.code === 'EEXIST') { const commanderError = new CommanderError( 1, e.code, `Temporary file already exists: ${tmpFilepath}. Delete this file and try again.`, ); commanderError.nestedError = e.message; throw commanderError; } else { throw e; } } } /** * Pretty prints Nargo.toml contents to a string * @param config - Nargo.toml contents * @returns The Nargo.toml contents as a string */ export function prettyPrintNargoToml(config: NoirPackageConfig): string { const withoutDependencies = Object.fromEntries(Object.entries(config).filter(([key]) => key !== 'dependencies')); const partialToml = TOML.stringify(withoutDependencies); const dependenciesToml = Object.entries(config.dependencies).map(([name, dep]) => { const depToml = TOML.stringify.value(dep); return `${name} = ${depToml}`; }); return partialToml + '\n[dependencies]\n' + dependenciesToml.join('\n') + '\n'; }