Skip to content

Commit 5f41550

Browse files
author
Fastace
committed
Fix:Restic恢复APP路径流程均修复;Bug:下一步调用恢复有问题,待修复
1 parent 6eb93bc commit 5f41550

2 files changed

Lines changed: 114 additions & 41 deletions

File tree

source/core/restic/src/main/kotlin/com/xayah/core/restic/ResticRepository.kt

Lines changed: 107 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,21 @@ class ResticRepository @Inject constructor(
126126
password: String,
127127
snapshotId: String,
128128
targetPath: String,
129+
snapshotSubPath: String? = null,
129130
includePath: String? = null,
130131
progressCallback: ResticProgressCallback? = null
131132
): Boolean {
132133
return withContext(Dispatchers.IO) {
133134
try {
135+
// 构造带子路径的快照ID
136+
val fullSnapshotId = if (!snapshotSubPath.isNullOrEmpty()) {
137+
"$snapshotId:$snapshotSubPath"
138+
} else {
139+
snapshotId
140+
}
141+
134142
val args = mutableListOf(
135-
resticPath, "restore", snapshotId,
143+
resticPath, "restore", fullSnapshotId,
136144
"--repo", repoPath,
137145
"--target", targetPath,
138146
"--json"
@@ -152,56 +160,117 @@ class ResticRepository @Inject constructor(
152160
processBuilder.environment()["XDG_CACHE_HOME"] = File(context.cacheDir, "restic").absolutePath
153161
val process = processBuilder.start()
154162

155-
// 分别读取标准输出和错误输出
156-
val stdout = process.inputStream.bufferedReader()
157-
val stderr = process.errorStream.bufferedReader()
158-
159-
// 处理标准输出(进度信息)
160-
stdout.use { reader ->
161-
reader.forEachLine { line ->
162-
try {
163-
val progress = parseRestoreProgress(line)
164-
if (progress != null && progressCallback != null) {
165-
progressCallback.onProgress(
166-
filesFinished = progress.files_finished ?: 0,
167-
filesTotal = progress.files_total ?: 0,
168-
bytesWritten = progress.bytes_written ?: 0,
169-
bytesTotal = progress.bytes_total ?: 0,
170-
filesSkipped = progress.files_skipped ?: 0,
171-
bytesSkipped = progress.bytes_skipped ?: 0
172-
)
163+
try {
164+
// 分别读取标准输出和错误输出
165+
val stdout = process.inputStream.bufferedReader()
166+
val stderr = process.errorStream.bufferedReader()
167+
168+
// 处理标准输出(进度信息)
169+
val outputBuilder = StringBuilder()
170+
stdout.use { reader ->
171+
reader.forEachLine { line ->
172+
outputBuilder.appendLine(line) // 捕获输出
173+
174+
try {
175+
val progress = parseRestoreProgress(line)
176+
if (progress != null && progressCallback != null) {
177+
progressCallback.onProgress(
178+
filesFinished = progress.files_finished ?: 0,
179+
filesTotal = progress.files_total ?: 0,
180+
bytesWritten = progress.bytes_written ?: 0,
181+
bytesTotal = progress.bytes_total ?: 0,
182+
filesSkipped = progress.files_skipped ?: 0,
183+
bytesSkipped = progress.bytes_skipped ?: 0
184+
)
185+
}
186+
} catch (e: Exception) {
187+
Log.w(TAG, "Failed to parse progress line: $line", e)
173188
}
174-
} catch (e: Exception) {
175-
Log.w(TAG, "Failed to parse progress line: $line", e)
176189
}
177190
}
178-
}
179191

180-
// 读取错误输出用于调试
181-
val errorOutput = stderr.readText()
182-
if (errorOutput.isNotEmpty()) {
183-
Log.e(TAG, "Restic restore error: $errorOutput")
184-
}
185-
val output = stdout.readText()
192+
// 读取错误输出用于调试
193+
val errorOutput = stderr.readText()
194+
val output = outputBuilder.toString() // 使用捕获的输出
186195

187-
val exitCode = process.waitFor()
196+
val exitCode = process.waitFor()
188197

189-
// 添加详细日志
190-
Log.d(TAG, "Restic restore exit code: $exitCode")
191-
if (exitCode != 0) {
192-
Log.e(TAG, "Restic restore error output: $errorOutput")
193-
}
194-
Log.d(TAG, "Restic restore output: $output")
198+
// === 详细恢复过程诊断 ===
199+
Log.d(TAG, "========== Restic 恢复过程详情 ==========")
200+
Log.d(TAG, "命令: ${args.joinToString(" ")}")
201+
Log.d(TAG, "退出码: $exitCode")
202+
Log.d(TAG, "标准输出长度: ${output.length} 字符")
203+
Log.d(TAG, "错误输出长度: ${errorOutput.length} 字符")
195204

196-
logger.logCommandResult(exitCode, output)
197-
exitCode == 0
205+
if (output.isNotEmpty()) {
206+
Log.d(TAG, "=== 标准输出内容 ===")
207+
output.lines().forEachIndexed { index, line ->
208+
Log.d(TAG, "stdout[$index]: $line")
209+
}
210+
}
211+
212+
if (errorOutput.isNotEmpty()) {
213+
Log.e(TAG, "=== 错误输出内容 ===")
214+
errorOutput.lines().forEachIndexed { index, line ->
215+
Log.e(TAG, "stderr[$index]: $line")
216+
}
217+
}
218+
219+
// 分析退出码原因
220+
if (exitCode != 0) {
221+
Log.w(TAG, "=== 退出码分析 ===")
222+
when {
223+
errorOutput.contains("warning", ignoreCase = true) -> {
224+
Log.w(TAG, "✓ 检测到警告信息")
225+
}
226+
errorOutput.contains("error", ignoreCase = true) -> {
227+
Log.e(TAG, "✗ 检测到错误信息")
228+
}
229+
errorOutput.contains("file not found", ignoreCase = true) -> {
230+
Log.e(TAG, "✗ 文件未找到")
231+
}
232+
errorOutput.contains("permission denied", ignoreCase = true) -> {
233+
Log.e(TAG, "✗ 权限被拒绝")
234+
}
235+
output.contains("restoring", ignoreCase = true) -> {
236+
Log.w(TAG, "✓ 检测到恢复操作记录")
237+
}
238+
else -> {
239+
Log.w(TAG, "? 未知原因的非零退出码")
240+
}
241+
}
242+
243+
// 检查目标文件
244+
val targetFile = File(targetPath, includePath ?: "")
245+
Log.w(TAG, "目标文件检查: ${targetFile.absolutePath}")
246+
Log.w(TAG, "文件存在: ${targetFile.exists()}")
247+
if (targetFile.exists()) {
248+
Log.w(TAG, "文件大小: ${targetFile.length()} bytes")
249+
Log.w(TAG, "文件修改时间: ${targetFile.lastModified()}")
250+
}
251+
}
252+
253+
Log.d(TAG, "========================================")
254+
255+
logger.logCommandResult(exitCode, output)
256+
exitCode == 0
257+
} catch (e: Exception) {
258+
Log.e(TAG, "Restic restore process exception", e)
259+
// 尝试获取可能的错误输出
260+
try {
261+
val errorOutput = process.errorStream.bufferedReader().readText()
262+
Log.e(TAG, "Process error output: $errorOutput")
263+
} catch (ex: Exception) {
264+
Log.e(TAG, "Failed to read error output", ex)
265+
}
266+
throw e
267+
}
198268
} catch (e: Exception) {
199269
logger.logCommandFailed(e)
200270
false
201271
}
202272
}
203273
}
204-
205274
// 添加进度解析方法
206275
private fun parseRestoreProgress(line: String): ResticRestoreProgress? {
207276
return try {

source/feature/main/restore/src/main/kotlin/com/xayah/feature/main/restore/ResticRestoreViewModel.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,16 +177,20 @@ class ResticRestoreViewModel @Inject constructor(
177177

178178
val targetPath = "${context.localBackupSaveDir()}/restore/"
179179
Log.d("ResticRestore", "恢复到用户备份目录: $targetPath")
180-
// 构造 include 路径:指定快照中要恢复的确切文件
181-
val includePath = "${targetPath}apps/${backup.packageName}/user_${backup.userId}/${backup.dataType.type}.tar.zst"
180+
val backupBaseDir = context.readBackupDirectory() ?: context.localBackupSaveDir()
181+
val snapshotSubPath = "$backupBaseDir/apps/${backup.packageName}/user_${backup.userId}"
182+
val includePath = "${backup.dataType.type}.tar.zst"
183+
val fullTargetPath = "${targetPath}apps/${backup.packageName}/user_${backup.userId}/"
182184
Log.d("ResticRestore", "恢复 ${backup.dataType.type} 到目标: $targetPath")
185+
Log.d("ResticRestore", "快照子路径: $snapshotSubPath")
183186
Log.d("ResticRestore", "包含文件: $includePath")
184187
val success = resticRepo.restoreSnapshot(
185188
repoPath = repoPath,
186189
password = password,
187190
snapshotId = backup.snapshotId,
188-
targetPath = targetPath,
191+
targetPath = fullTargetPath,
189192
includePath = includePath,
193+
snapshotSubPath = snapshotSubPath,
190194
progressCallback = progressCallback
191195
)
192196

0 commit comments

Comments
 (0)