(
src: string,
dest: string,
ensureDir: (dirPath: string) => void,
stats: CopyStats = { copied: 0, skipped: 0, errors: [] }
)
| 132 | * @returns 复制结果统计 |
| 133 | */ |
| 134 | export function copyDirMerge( |
| 135 | src: string, |
| 136 | dest: string, |
| 137 | ensureDir: (dirPath: string) => void, |
| 138 | stats: CopyStats = { copied: 0, skipped: 0, errors: [] } |
| 139 | ): CopyStats { |
| 140 | if (!fs.existsSync(src)) return stats |
| 141 | |
| 142 | try { |
| 143 | ensureDir(dest) |
| 144 | const entries = fs.readdirSync(src, { withFileTypes: true }) |
| 145 | |
| 146 | for (const entry of entries) { |
| 147 | const srcPath = path.join(src, entry.name) |
| 148 | const destPath = path.join(dest, entry.name) |
| 149 | |
| 150 | try { |
| 151 | if (entry.isDirectory()) { |
| 152 | if (!fs.existsSync(destPath)) { |
| 153 | copyDirRecursive(srcPath, destPath, ensureDir) |
| 154 | stats.copied++ |
| 155 | } else { |
| 156 | copyDirMerge(srcPath, destPath, ensureDir, stats) |
| 157 | } |
| 158 | } else { |
| 159 | if (!fs.existsSync(destPath)) { |
| 160 | fs.copyFileSync(srcPath, destPath) |
| 161 | stats.copied++ |
| 162 | } else { |
| 163 | stats.skipped++ |
| 164 | } |
| 165 | } |
| 166 | } catch (error) { |
| 167 | const errorMsg = `复制失败: ${srcPath} -> ${error instanceof Error ? error.message : String(error)}` |
| 168 | console.error('[Paths]', errorMsg) |
| 169 | stats.errors.push(errorMsg) |
| 170 | } |
| 171 | } |
| 172 | } catch (error) { |
| 173 | const errorMsg = `读取目录失败: ${src} -> ${error instanceof Error ? error.message : String(error)}` |
| 174 | console.error('[Paths]', errorMsg) |
| 175 | stats.errors.push(errorMsg) |
| 176 | } |
| 177 | |
| 178 | return stats |
| 179 | } |
| 180 | |
| 181 | /** |
| 182 | * 写入迁移日志到 app.log |
no test coverage detected