-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathProgressView.swift
110 lines (100 loc) · 4.28 KB
/
ProgressView.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import BEP
import SwiftProtobuf
import XCBProtocol
struct ProgressView {
let progress: Int32
let totalActions: Int32
let count: Int32
let message: String
let progressPercent: Double
init(progress: Int32, totalActions: Int32, count: Int32, message: String, progressPercent: Double) {
self.progress = progress
self.totalActions = totalActions
self.count = count
self.message = message
self.progressPercent = progressPercent
}
init?(event: BuildEventStream_BuildEvent, last: ProgressView?) {
let count = event.id.progress.opaqueCount
let lastProgress = last?.progress ?? 0
let lastTotalActions = last?.totalActions ?? 0
let lastCount = last?.count ?? 0
guard count > 0 else {
return nil
}
let progressStderr = event.progress.stderr
let (ranActions, totalActions) = ProgressView.extractUIProgress(progressStderr: progressStderr)
var baseProgress: Int32
if ranActions == 0 {
// Update the base progress with the last progress. This is
// a synthetic number. Bazel will not update for all actions
baseProgress = lastProgress + (count - lastCount)
} else {
baseProgress = ranActions
}
let progressTotalActions = max(lastTotalActions, totalActions)
let progress = min(progressTotalActions, max(lastProgress, baseProgress))
// Don't notify for the same progress more than once.
if progressTotalActions > 0, progress == lastProgress, progressTotalActions == lastTotalActions {
return nil
}
var message: String
var progressPercent: Double = -1.0
if progressTotalActions > 0 {
// Pad this to prevent some strange UI
message = "\(progress) of \(progressTotalActions) tasks "
// Very early on in a build, totalActions is not fully computed, and if we set it here
// the progress bar will jump to 100. Leave it at -1.0 until we get further along.
// Generally, for an Xcode target there will be a codesign, link, and compile action.
// Consider using a timestamp as an alternative?
if progressTotalActions > 5 {
progressPercent = (Double(progress) / Double(progressTotalActions)) * 100.0
}
} else if progressStderr.count > 28 {
// Any more than this and it crashes or looks bad.
// If Bazel hasn't reported anything resonable yet, then it's likely
// likely still analyzing. Render Bazels message
message = String(progressStderr.prefix(28)) + ".."
} else {
// This is really undefined behavior but render the count.
message = "Updating \(progress)"
}
// At the last message, update to 100%
if event.lastMessage {
progressPercent = 99.0
}
self.init(progress: progress, totalActions: progressTotalActions,
count: count, message: String(message.prefix(30)), progressPercent:
progressPercent)
}
/// Look for progress like [22 / 228]
/// reference src/main/java/com/google/devtools/build/lib/buildtool/ExecutionProgressReceiver.java
public static func extractUIProgress(progressStderr: String) -> (Int32, Int32) {
var ranActions: Int32 = 0
var totalActions: Int32 = 0
if progressStderr.first == "[" {
var numberStrings: [String] = []
var accum = ""
for x in progressStderr {
if x == "[" {
continue
} else if x == "]" {
numberStrings.append(accum)
break
} else if x == " " || x == "/" {
if accum.count > 0 {
numberStrings.append(accum)
accum = ""
}
} else {
accum.append(x)
}
}
if numberStrings.count == 2 {
ranActions = Int32(numberStrings[0].replacingOccurrences(of: ",", with: "")) ?? 0
totalActions = Int32(numberStrings[1].replacingOccurrences(of: ",", with: "")) ?? 0
}
}
return (ranActions, totalActions)
}
}