v0.9.4: add doctor diagnostics
This commit is contained in:
@@ -97,6 +97,8 @@ func run(args []string, stdout, stderr io.Writer, bridge photos.Bridge) int {
|
||||
return cmdManifest(args[1:], stdout, stderr)
|
||||
case "cleanup":
|
||||
return cmdCleanup(args[1:], stdout, stderr)
|
||||
case "doctor":
|
||||
return cmdDoctor(args[1:], stdout, stderr, bridge)
|
||||
case "retry-failed":
|
||||
return cmdRetryFailed(args[1:], stdout, stderr, bridge)
|
||||
case "failures":
|
||||
@@ -144,6 +146,7 @@ USAGE
|
||||
photoscli verify --out <dir> [--manifest jsonl|sqlite]
|
||||
photoscli manifest repair --out <dir> [--manifest jsonl|sqlite] [--checksum sha256] [--dry-run]
|
||||
photoscli cleanup --out <dir> [--manifest jsonl|sqlite] [--dry-run]
|
||||
photoscli doctor [--out <dir>] [--manifest jsonl|sqlite] [--json]
|
||||
photoscli retry-failed --out <dir>
|
||||
photoscli retry-failed --out <dir> --clear-on-success
|
||||
photoscli failures list --out <dir>
|
||||
@@ -195,6 +198,9 @@ COMMANDS
|
||||
cleanup --out <dir> [--manifest jsonl|sqlite] [--dry-run]
|
||||
Remove files not referenced by the manifest. Use --dry-run first.
|
||||
|
||||
doctor [--out <dir>] [--manifest jsonl|sqlite] [--json]
|
||||
Check Photos access and optional backup/manifest health without changing data.
|
||||
|
||||
retry-failed --out <dir>
|
||||
Retry assets previously written to failures.jsonl.
|
||||
|
||||
@@ -2396,6 +2402,64 @@ func verifySidecar(stdout io.Writer, outDir, id, checkPath string, strict bool)
|
||||
return 0
|
||||
}
|
||||
|
||||
func cmdDoctor(args []string, stdout, stderr io.Writer, bridge photos.Bridge) int {
|
||||
result := map[string]any{"photos_access": "ok"}
|
||||
problems := 0
|
||||
if rc := mustAuth(stderr, bridge); rc != exitOK {
|
||||
result["photos_access"] = "denied"
|
||||
problems++
|
||||
}
|
||||
outDir := flagVal(args, "--out")
|
||||
if outDir != "" {
|
||||
result["out"] = outDir
|
||||
if info, err := statFunc(outDir); err != nil || !info.IsDir() {
|
||||
result["backup_dir"] = "missing"
|
||||
problems++
|
||||
} else {
|
||||
result["backup_dir"] = "ok"
|
||||
mf, err := manifest.ParseFormat(flagValWithDefault(args, "--manifest", "jsonl"))
|
||||
if err != nil {
|
||||
fmt.Fprintf(stderr, "error: %v\n", err)
|
||||
return exitErr
|
||||
}
|
||||
entries, err := loadManifestEntries(outDir, mf)
|
||||
if err != nil {
|
||||
result["manifest"] = "error"
|
||||
problems++
|
||||
} else {
|
||||
result["manifest"] = string(mf)
|
||||
result["entries"] = len(entries)
|
||||
}
|
||||
failures := loadFailures(outDir)
|
||||
result["failures"] = len(failures)
|
||||
if len(failures) > 0 {
|
||||
problems++
|
||||
}
|
||||
}
|
||||
}
|
||||
if hasFlag(args, "--json") {
|
||||
result["problems"] = problems
|
||||
if err := json.NewEncoder(stdout).Encode(result); err != nil {
|
||||
fmt.Fprintf(stderr, "error: %v\n", err)
|
||||
return exitErr
|
||||
}
|
||||
} else {
|
||||
keys := make([]string, 0, len(result))
|
||||
for k := range result {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
fmt.Fprintf(stdout, "%s\t%v\n", k, result[k])
|
||||
}
|
||||
fmt.Fprintf(stdout, "problems\t%d\n", problems)
|
||||
}
|
||||
if problems > 0 {
|
||||
return exitPartial
|
||||
}
|
||||
return exitOK
|
||||
}
|
||||
|
||||
func cmdCleanup(args []string, stdout, stderr io.Writer) int {
|
||||
outDir := flagVal(args, "--out")
|
||||
if outDir == "" {
|
||||
|
||||
Reference in New Issue
Block a user