Class: GDKBox::Docker::PullProgress
- Inherits:
-
Object
- Object
- GDKBox::Docker::PullProgress
- Defined in:
- lib/gdkbox/docker.rb
Overview
Parses the terminal output of docker pull (see Shell#stream_tty) into an
overall completion fraction and a download rate. Docker repaints one line
per layer, each shaped like "
Constant Summary collapse
- DONE =
States that mark a layer as fully pulled.
["Pull complete", "Already exists"].freeze
- SAMPLE_INTERVAL =
Docker repaints many times a second across parallel layers; recomputing speed on every burst line would divide a small byte delta by a near-zero time and report absurd spikes. Instead accumulate bytes and only recompute the rate once this much time has elapsed.
0.25- UNITS =
SI byte units as docker prints them (base 1000).
{ "B" => 1, "kB" => 1000, "MB" => 1000**2, "GB" => 1000**3, "TB" => 1000**4 }.freeze
Instance Method Summary collapse
-
#completed ⇒ Object
Number of layers fully pulled so far.
-
#fraction ⇒ Object
Overall progress in 0.0..1.0 (0.0 before any layer is known).
-
#human_speed ⇒ Object
Current download speed as a human string (e.g. "12.3 MB/s"), or nil.
- #ingest(line) ⇒ Object
-
#initialize(clock: nil) ⇒ PullProgress
constructor
clockreturns a monotonically increasing time in seconds; it is injected in tests so speed is deterministic. -
#speed ⇒ Object
Current download speed in bytes/second, or nil before it can be measured (needs two samples with elapsed time and new bytes).
-
#total ⇒ Object
Number of distinct layers seen so far.
Constructor Details
#initialize(clock: nil) ⇒ PullProgress
clock returns a monotonically increasing time in seconds; it is
injected in tests so speed is deterministic.
61 62 63 64 65 66 67 |
# File 'lib/gdkbox/docker.rb', line 61 def initialize(clock: nil) @layers = {} @downloaded = Hash.new(0) # layer id => bytes pulled so far @sizes = {} # layer id => total bytes (once known) @clock = clock || -> { Process.clock_gettime(Process::CLOCK_MONOTONIC) } @speed = nil # bytes/second, or nil until measurable end |
Instance Method Details
#completed ⇒ Object
Number of layers fully pulled so far.
80 81 82 |
# File 'lib/gdkbox/docker.rb', line 80 def completed @layers.count { |_id, value| value >= 1.0 } end |
#fraction ⇒ Object
Overall progress in 0.0..1.0 (0.0 before any layer is known).
90 91 92 93 94 |
# File 'lib/gdkbox/docker.rb', line 90 def fraction return 0.0 if @layers.empty? @layers.values.sum / @layers.size end |
#human_speed ⇒ Object
Current download speed as a human string (e.g. "12.3 MB/s"), or nil.
103 104 105 106 107 |
# File 'lib/gdkbox/docker.rb', line 103 def human_speed return nil unless @speed && @speed.positive? "#{human_size(@speed)}/s" end |
#ingest(line) ⇒ Object
69 70 71 72 73 74 75 76 77 |
# File 'lib/gdkbox/docker.rb', line 69 def ingest(line) id, status = line.split(": ", 2) return unless status # The first line ("<tag>: Pulling from <repo>") is not a layer. return if status.start_with?("Pulling from") track_bytes(id, status) @layers[id] = score(status) end |
#speed ⇒ Object
Current download speed in bytes/second, or nil before it can be measured (needs two samples with elapsed time and new bytes).
98 99 100 |
# File 'lib/gdkbox/docker.rb', line 98 def speed @speed end |
#total ⇒ Object
Number of distinct layers seen so far.
85 86 87 |
# File 'lib/gdkbox/docker.rb', line 85 def total @layers.size end |