* Restores a file from its backup path with proper directory creation and permissions. * Lazy mkdir: tries copyFile first, creates the directory on ENOENT.
( filePath: string, backupFileName: string, )
| 802 | * Lazy mkdir: tries copyFile first, creates the directory on ENOENT. |
| 803 | */ |
| 804 | async function restoreBackup( |
| 805 | filePath: string, |
| 806 | backupFileName: string, |
| 807 | ): Promise<void> { |
| 808 | const backupPath = resolveBackupPath(backupFileName) |
| 809 | |
| 810 | // Stat first: if the backup is missing, log and bail before attempting |
| 811 | // the copy. Separates "backup missing" from "destination dir missing". |
| 812 | let backupStats: Stats |
| 813 | try { |
| 814 | backupStats = await stat(backupPath) |
| 815 | } catch (e: unknown) { |
| 816 | if (isENOENT(e)) { |
| 817 | logEvent('tengu_file_history_rewind_restore_file_failed', {}) |
| 818 | logError( |
| 819 | new Error(`FileHistory: [Rewind] Backup file not found: ${backupPath}`), |
| 820 | ) |
| 821 | return |
| 822 | } |
| 823 | throw e |
| 824 | } |
| 825 | |
| 826 | // Lazy mkdir: 99% of calls hit the fast path (destination dir exists). |
| 827 | try { |
| 828 | await copyFile(backupPath, filePath) |
| 829 | } catch (e: unknown) { |
| 830 | if (!isENOENT(e)) throw e |
| 831 | await mkdir(dirname(filePath), { recursive: true }) |
| 832 | await copyFile(backupPath, filePath) |
| 833 | } |
| 834 | |
| 835 | // Restore the file permissions |
| 836 | await chmod(filePath, backupStats.mode) |
| 837 | } |
| 838 | |
| 839 | /** |
| 840 | * Gets the first (earliest) backup version for a file, used when rewinding |
no test coverage detected