Module: Everywhere::UI

Defined in:
lib/everywhere/ui.rb

Overview

Terminal output helpers. Colors follow the informal standard: on when stdout is a TTY or CLICOLOR_FORCE=1, always off when NO_COLOR is set.

The hosted runner streams every release through a pipe (not a TTY) into the Platform web log, so it exports CLICOLOR_FORCE=1 to keep our color — the web UI renders ANSI. That's why we force rather than sniff the TTY there.

Class Method Summary collapse

Class Method Details

.bad(msg) ⇒ Object



59
# File 'lib/everywhere/ui.rb', line 59

def bad(msg)     = puts(bad_line(msg))

.bad_line(msg) ⇒ Object



50
# File 'lib/everywhere/ui.rb', line 50

def bad_line(msg)     = "#{red("")} #{msg}"

.blue(t) ⇒ Object



29
# File 'lib/everywhere/ui.rb', line 29

def blue(t)    = paint(t, 34)

.bold(t) ⇒ Object



24
# File 'lib/everywhere/ui.rb', line 24

def bold(t)    = paint(t, 1)

.color?Boolean

Returns:

  • (Boolean)


13
14
15
16
17
18
# File 'lib/everywhere/ui.rb', line 13

def color?
  return false if ENV["NO_COLOR"]
  return true if ENV["CLICOLOR_FORCE"] == "1"

  $stdout.tty?
end

.cyan(t) ⇒ Object



31
# File 'lib/everywhere/ui.rb', line 31

def cyan(t)    = paint(t, 36)

.detail(msg) ⇒ Object



57
# File 'lib/everywhere/ui.rb', line 57

def detail(msg)  = puts(detail_line(msg))

.detail_line(msg) ⇒ Object



48
# File 'lib/everywhere/ui.rb', line 48

def detail_line(msg)  = "    #{gray("·")} #{gray(msg)}"

.die!(msg) ⇒ Object



71
72
73
# File 'lib/everywhere/ui.rb', line 71

def die!(msg)
  abort "#{red("")} #{red(msg)}"
end

.dim(t) ⇒ Object



25
# File 'lib/everywhere/ui.rb', line 25

def dim(t)     = paint(t, 2)

.gray(t) ⇒ Object

bright black — dimmer than dim() on most themes



32
# File 'lib/everywhere/ui.rb', line 32

def gray(t)    = paint(t, 90) # bright black — dimmer than dim() on most themes

.green(t) ⇒ Object



27
# File 'lib/everywhere/ui.rb', line 27

def green(t)   = paint(t, 32)

.magenta(t) ⇒ Object



30
# File 'lib/everywhere/ui.rb', line 30

def magenta(t) = paint(t, 35)

.note(msg, marker: "·", color: :gray) ⇒ Object



69
# File 'lib/everywhere/ui.rb', line 69

def note(msg, marker: "·", color: :gray) = puts(note_line(msg, marker: marker, color: color))

.note_line(msg, marker: "·", color: :gray) ⇒ Object

An indented, dim outcome under a substep — e.g. "accepted", "valid on disk".



64
65
66
67
# File 'lib/everywhere/ui.rb', line 64

def note_line(msg, marker: "·", color: :gray)
  tint = respond_to?(color) ? method(color) : method(:gray)
  "    #{tint.call(marker)} #{tint.call(msg)}"
end

.ok(msg) ⇒ Object



58
# File 'lib/everywhere/ui.rb', line 58

def ok(msg)      = puts(ok_line(msg))

.ok_line(msg) ⇒ Object



49
# File 'lib/everywhere/ui.rb', line 49

def ok_line(msg)      = "#{green("")} #{msg}"

.paint(text, *codes) ⇒ Object



20
21
22
# File 'lib/everywhere/ui.rb', line 20

def paint(text, *codes)
  color? ? "\e[#{codes.join(";")}m#{text}\e[0m" : text.to_s
end

.phase(msg) ⇒ Object



54
# File 'lib/everywhere/ui.rb', line 54

def phase(msg)   = puts(phase_line(msg))

.phase_line(msg) ⇒ Object

--- output levels --------------------------------------------------------

phase   ●  a major phase boundary (build / sign / notarize)
step    →  a top-level action inside a phase
substep ▸  a sub-action under a step (indented)
detail  ·  raw-ish detail under a substep (indented + dim)

Every level has a *_line string builder (used by LogFilter, which returns lines for someone else to print) and a printer that puts it. ok / success / warn / bad / die! carry outcomes at any level.



45
# File 'lib/everywhere/ui.rb', line 45

def phase_line(msg)   = "\n#{bold(cyan(""))} #{bold(msg)}"

.red(t) ⇒ Object



26
# File 'lib/everywhere/ui.rb', line 26

def red(t)     = paint(t, 31)

.short_path(str) ⇒ Object

Collapse the noisy machine paths that external tools echo (codesign, notarytool, stapler) down to something a human can scan. In particular the runner works out of a deep /var/folders/…/every-runner…/src/ sandbox — we strip that prefix so only the meaningful dist/App.app tail remains. Then $HOME → ~ and the cwd → a leading (dropped) prefix.



85
86
87
88
89
90
91
92
93
94
# File 'lib/everywhere/ui.rb', line 85

def short_path(str)
  s = str.to_s.dup
  # Runner/local temp sandboxes: keep only the part after the extracted src/.
  s = s.gsub(%r{/(?:private/)?(?:var|tmp)/[^\s"']*?/every-[a-z]+[0-9A-Za-z_-]+/src/}, "")
  # Any other everywhere-* scratch dir: keep the basename tail.
  s = s.gsub(%r{/(?:private/)?(?:var|tmp)/[^\s"']*?/everywhere-[a-z]+[0-9A-Za-z_.-]*/}, "")
  home = ENV["HOME"]
  s = s.gsub("#{home}/", "~/") if home && !home.empty?
  s
end

.step(msg) ⇒ Object



55
# File 'lib/everywhere/ui.rb', line 55

def step(msg)    = puts(step_line(msg))

.step_line(msg) ⇒ Object



46
# File 'lib/everywhere/ui.rb', line 46

def step_line(msg)    = "#{cyan("")} #{msg}"

.substep(msg) ⇒ Object



56
# File 'lib/everywhere/ui.rb', line 56

def substep(msg) = puts(substep_line(msg))

.substep_line(msg) ⇒ Object



47
# File 'lib/everywhere/ui.rb', line 47

def substep_line(msg) = "  #{cyan("")} #{msg}"

.success(msg) ⇒ Object



61
# File 'lib/everywhere/ui.rb', line 61

def success(msg) = puts(success_line(msg))

.success_line(msg) ⇒ Object



52
# File 'lib/everywhere/ui.rb', line 52

def success_line(msg) = "#{green("")} #{bold(msg)}"

.warn(msg) ⇒ Object



60
# File 'lib/everywhere/ui.rb', line 60

def warn(msg)    = puts(warn_line(msg))

.warn_line(msg) ⇒ Object



51
# File 'lib/everywhere/ui.rb', line 51

def warn_line(msg)    = "#{yellow("!")} #{msg}"

.yellow(t) ⇒ Object



28
# File 'lib/everywhere/ui.rb', line 28

def yellow(t)  = paint(t, 33)

.yn(bool) ⇒ Object

A yes/no fact, colored by truthiness (for signing receipts).



76
# File 'lib/everywhere/ui.rb', line 76

def yn(bool) = bool ? green("yes") : red("no")