Skip to content

Commit e66882c

Browse files
committed
try to fix launcher docker pull status
1 parent 981d1c9 commit e66882c

2 files changed

Lines changed: 26 additions & 22 deletions

File tree

app/macos/Sources/OpenClawLib/OpenClawLauncher.swift

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -839,7 +839,7 @@ public class OpenClawLauncher: ObservableObject {
839839
}
840840

841841
private func ensureImage() async throws {
842-
addStep(.running, "Pulling latest image... this may take a moment")
842+
addStep(.running, "Pulling latest image... first time may take a few minutes")
843843
pullProgressText = nil
844844

845845
let pullExitCode: Int
@@ -869,34 +869,35 @@ public class OpenClawLauncher: ObservableObject {
869869
}
870870

871871
/// Streams `docker pull` output and updates `pullProgressText` with download progress.
872+
/// Uses `--progress=plain` for predictable newline-delimited output across Docker versions.
873+
/// Progress text is purely cosmetic — exit code alone determines success/failure.
872874
private func pullImageWithProgress(_ image: String) async -> Int32 {
873875
let process = Process()
874-
let stderrPipe = Pipe()
876+
let outputPipe = Pipe()
875877

876878
process.executableURL = URL(fileURLWithPath: "/usr/bin/env")
877-
process.arguments = ["docker", "pull", image]
878-
process.standardOutput = FileHandle.nullDevice
879-
process.standardError = stderrPipe
879+
process.arguments = ["docker", "pull", "--progress=plain", image]
880+
process.standardOutput = outputPipe
881+
process.standardError = outputPipe // merge stderr into same pipe
880882
process.environment = DockerPaths.augmentedEnvironment()
881883

882884
do {
883885
try process.run()
884886
} catch {
885-
logger.error("pullImageWithProgress: failed to start process: \(error.localizedDescription)")
887+
logger.error("pullImageWithProgress: failed to start: \(error.localizedDescription)")
886888
return -1
887889
}
888890

889-
// Read stderr incrementally in background and parse progress
891+
// Read output incrementally — purely cosmetic, failures are silent
890892
let progressTask = Task.detached { [weak self] () -> Void in
891-
let handle = stderrPipe.fileHandleForReading
893+
let handle = outputPipe.fileHandleForReading
892894
var buffer = Data()
893895

894896
while true {
895897
let chunk = handle.availableData
896898
if chunk.isEmpty { break } // EOF
897899
buffer.append(chunk)
898900

899-
// Parse complete lines from buffer
900901
if let text = String(data: buffer, encoding: .utf8) {
901902
let summary = Self.parsePullProgress(text)
902903
if let summary = summary {
@@ -914,12 +915,13 @@ public class OpenClawLauncher: ObservableObject {
914915
return process.terminationStatus
915916
}
916917

917-
/// Parse docker pull stderr output to produce a human-readable progress summary.
918-
/// Docker pull output has lines like: "abc123: Downloading [===> ] 50.12MB/400MB"
919-
/// We aggregate all "Downloading" layers into a total.
918+
/// Parse docker pull output to produce a human-readable progress summary.
919+
/// With `--progress=plain`, output is newline-delimited:
920+
/// "abc123: Downloading 50.12MB / 400MB"
921+
/// "abc123: Download complete"
922+
/// Returns nil if nothing parseable (graceful fallback to static hint).
920923
nonisolated static func parsePullProgress(_ output: String) -> String? {
921-
let lines = output.split(separator: "\r").last.map { String($0) } ?? output
922-
let allLines = lines.split(separator: "\n")
924+
let allLines = output.components(separatedBy: .newlines)
923925

924926
var totalDownloaded: Double = 0
925927
var totalSize: Double = 0
@@ -928,17 +930,15 @@ public class OpenClawLauncher: ObservableObject {
928930
var extractingCount = 0
929931

930932
for line in allLines {
931-
let s = String(line)
932-
if s.contains("Downloading") {
933+
if line.contains("Downloading") {
933934
downloadingCount += 1
934-
// Parse "50.12MB/400MB" from the line
935-
if let (downloaded, size) = parseSizeFromLine(s) {
935+
if let (downloaded, size) = parseSizeFromLine(line) {
936936
totalDownloaded += downloaded
937937
totalSize += size
938938
}
939-
} else if s.contains("Download complete") || s.contains("Already exists") || s.contains("Pull complete") {
939+
} else if line.contains("Download complete") || line.contains("Already exists") || line.contains("Pull complete") {
940940
doneCount += 1
941-
} else if s.contains("Extracting") {
941+
} else if line.contains("Extracting") {
942942
extractingCount += 1
943943
}
944944
}

app/macos/Sources/OpenClawLib/Views/NewLauncherView.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,12 @@ public struct NewLauncherView: View {
233233
time = nil
234234
case .running:
235235
status = .active
236-
// Show pull progress for the "Container image" step
237-
time = mapping.label == "Container image" ? launcher.pullProgressText : nil
236+
// Show pull progress for the "Container image" step, with static fallback
237+
if mapping.label == "Container image" {
238+
time = launcher.pullProgressText ?? "may take a few minutes"
239+
} else {
240+
time = nil
241+
}
238242
case .error:
239243
status = .error
240244
time = "failed"

0 commit comments

Comments
 (0)