(absPath: string, data: string)
| 644 | * user's data and are just clutter. |
| 645 | */ |
| 646 | export async function writeFileAtomic(absPath: string, data: string): Promise<void> { |
| 647 | const tmp = `${absPath}.${process.pid}.${Date.now()}.tmp` |
| 648 | await fs.mkdir(path.dirname(absPath), { recursive: true }) |
| 649 | const handle = await fs.open(tmp, 'w') |
| 650 | try { |
| 651 | await handle.writeFile(data, 'utf8') |
| 652 | try { |
| 653 | await handle.sync() |
| 654 | } catch (syncErr) { |
| 655 | console.warn('fsync failed for atomic write', syncErr) |
| 656 | } |
| 657 | } finally { |
| 658 | await handle.close() |
| 659 | } |
| 660 | try { |
| 661 | await fs.rename(tmp, absPath) |
| 662 | } catch (err) { |
| 663 | try { |
| 664 | await fs.unlink(tmp) |
| 665 | } catch { |
| 666 | /* ignore */ |
| 667 | } |
| 668 | throw err |
| 669 | } |
| 670 | } |
| 671 | |
| 672 | export async function updateConfig( |
| 673 | updater: (cfg: PersistedConfig) => PersistedConfig | Promise<PersistedConfig> |
no test coverage detected