squared 0.3.4 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -28,12 +28,16 @@ module Squared
28
28
  bright_cyan!: '106',
29
29
  bright_white!: '107'
30
30
  }.freeze
31
+ AIX_GRAPH = ['│', '─', '├', '└', '┬'].freeze
32
+ AIX_BORDER = ['│', '─', '╭', '╮', '╯', '╰', '├', '┤', '┬', '┴'].freeze
31
33
  TEXT_STYLE = [:bold, :dim, :italic, :underline, :blinking, nil, :inverse, :hidden, :strikethrough].freeze
32
- private_constant :AIX_TERM, :TEXT_STYLE
34
+ private_constant :AIX_TERM, :AIX_GRAPH, :AIX_BORDER, :TEXT_STYLE
33
35
 
34
36
  def enable_aixterm
35
37
  unless (colors = __get__(:colors)).frozen?
36
38
  colors.merge!(AIX_TERM)
39
+ ARG[:GRAPH] = AIX_GRAPH
40
+ ARG[:BORDER] = AIX_BORDER
37
41
  end
38
42
  block_given? ? yield(self) : self
39
43
  end
@@ -166,16 +170,18 @@ module Squared
166
170
  color ? sub_style(ret, *styles) : ret
167
171
  end
168
172
 
169
- def log_message(level, *args, subject: nil, hint: nil, color: ARG[:COLOR])
173
+ def log_message(level, *args, subject: nil, hint: nil, color: ARG[:COLOR], pass: false)
174
+ return false if !pass && level.is_a?(::Numeric) && level < ARG[:LEVEL]
175
+
170
176
  args = args.map(&:to_s)
171
- if args.size > 1
177
+ if args.size > 1 && !hint
172
178
  title = log_title(level, color: false)
173
179
  sub = { pat: /^(#{title})(.+)$/, styles: __get__(:theme)[:logger][log_sym(level)] } if color
174
180
  emphasize(args, title: title + (subject ? " #{subject}" : ''), sub: sub)
175
181
  else
176
182
  msg = [log_title(level, color: color)]
177
183
  if subject
178
- msg << (color ? sub_style(subject, :underline) : subject)
184
+ msg << (color ? sub_style(subject, styles: (@theme && @theme[:subject]) || :bold) : subject)
179
185
  else
180
186
  msg += args
181
187
  args.clear
@@ -185,6 +191,8 @@ module Squared
185
191
  end
186
192
 
187
193
  def puts_oe(*args, pipe: 1)
194
+ return if args.first == false && args.size == 1
195
+
188
196
  if pipe.is_a?(Pathname)
189
197
  begin
190
198
  File.open(pipe, 'a') do |f|
@@ -226,27 +234,31 @@ module Squared
226
234
  require 'io/console'
227
235
  (n = [n, $stdout.winsize[1] - 4].min) rescue nil
228
236
  end
237
+ b0, b1, b2, b3, b4, b5, b6, b7 = ARG[:BORDER]
229
238
  out = []
230
- bord = '-' * (n + 4)
231
- bord = sub_style(bord, styles: border) if border
239
+ draw = lambda do |a, b|
240
+ ret = a + (b1 * (n + 2)) + b
241
+ ret = sub_style(ret, styles: border) if border
242
+ ret
243
+ end
232
244
  sub = as_a(sub)
233
245
  pr = lambda do |line|
234
246
  s = line.ljust(n)
235
247
  sub.each { |h| s = sub_style(s, **h) }
236
- s = "| #{s} |"
248
+ s = "#{b0} #{s} #{b0}"
237
249
  if border
238
- s = sub_style(s, pat: /\A(\|)(.+)\z/m, styles: border)
239
- s = sub_style(s, pat: /\A(.+)(\|)\z/m, styles: border, index: 2)
250
+ s = sub_style(s, pat: /\A(#{Regexp.escape(b0)})(.+)\z/m, styles: border)
251
+ s = sub_style(s, pat: /\A(.+)(#{Regexp.escape(b0)})\z/m, styles: border, index: 2)
240
252
  end
241
253
  s
242
254
  end
243
- out << bord
255
+ out << draw.(b2, b3)
244
256
  if title
245
257
  out += title.map { |t| pr.(t) }
246
- out << bord
258
+ out << draw.(b6, b7)
247
259
  end
248
260
  lines.each { |line| out << pr.(line) }
249
- out << bord
261
+ out << draw.(b5, b4)
250
262
  if footer
251
263
  unless sub.empty? && !right
252
264
  footer.map! do |s|
@@ -8,8 +8,8 @@ module Squared
8
8
  def confirm(msg, default = nil, agree: 'Y', cancel: 'N', attempts: 5, timeout: 15)
9
9
  require 'readline'
10
10
  require 'timeout'
11
- agree = /\A#{agree}\z/i if agree.is_a?(::String)
12
- cancel = /\A#{cancel}\z/i if cancel.is_a?(::String)
11
+ agree = /^#{agree}$/i if agree.is_a?(::String)
12
+ cancel = /^#{cancel}$/i if cancel.is_a?(::String)
13
13
  Timeout.timeout(timeout) do
14
14
  begin
15
15
  while (ch = Readline.readline(msg, true))
@@ -8,78 +8,91 @@ module Squared
8
8
  module Shell
9
9
  module_function
10
10
 
11
- def shell_escape(val, quote: false, force: false)
12
- if (data = /\A(--?[^= ]+)((=|\s+)(["'])?(.+?)(["'])?)?\z/m.match(val = val.to_s))
13
- return val if !data[2] || (!data[4] && data[5] =~ /\s/)
14
-
15
- join = ->(opt) { data[1] + data[3] + shell_quote(opt) }
16
- if data[4] == data[6]
17
- data[4] ? val : join.(data[5])
11
+ def shell_escape(val, quote: false, force: false, double: false, override: false)
12
+ if (r = /\A(--?)([^= ]+)((=|\s+)(["'])?(.+?)(["'])?)?\z/m.match(val = val.to_s))
13
+ return val if !r[3] || (!r[5] && r[6].match?(/\s/))
14
+
15
+ combine = lambda do |opt|
16
+ if r[2] =~ /^(["'])(.+)\1$/
17
+ double = $1 == '"'
18
+ r[2] = $2
19
+ override = true
20
+ end
21
+ r[1] + r[2] + r[4] + shell_quote(opt, double: double, force: force, override: override)
22
+ end
23
+ if r[5] == r[7]
24
+ r[5] ? val : combine.(r[6])
18
25
  else
19
- join.(data[4] + data[5] + data[6])
26
+ force = true
27
+ combine.(r[5] + r[6] + r[7])
20
28
  end
21
29
  elsif Rake::Win32.windows?
22
- quote ? shell_quote(val, force: force) : val
30
+ quote ? shell_quote(val, double: double, force: force) : val
23
31
  else
24
32
  Shellwords.escape(val)
25
33
  end
26
34
  end
27
35
 
28
- def shell_quote(val, force: true)
36
+ def shell_quote(val, option: true, force: true, double: false, override: false)
29
37
  val = val.to_s
30
- return val if (!force && !val.include?(' ')) || val.match?(/(?:^|\S=|[^=]\s+)(["']).+\1\z/m)
31
-
32
- Rake::Win32.windows? || ARG[:QUOTE] == '"' ? "\"#{double_quote(val)}\"" : "'#{single_quote(val)}'"
33
- end
34
-
35
- def shell_split(val, escape: true, quote: false, join: nil)
36
- val = Shellwords.split(val)
37
- val = val.map { |opt| shell_escape(opt, quote: quote) } if escape
38
- return val unless join
38
+ return val if (!force && !val.include?(' ')) || (option && val.match?(/(?:^|\S=|[^=]\s+)(["']).+\1\z/m))
39
39
 
40
- val.join(join.is_a?(::String) ? join : ' ')
40
+ if double || Rake::Win32.windows? || (ARG[:QUOTE] == '"' && !override)
41
+ "\"#{val.gsub(/(?<!\\)"/, '\\"')}\""
42
+ else
43
+ "'#{val.gsub("'", "'\\\\''")}'"
44
+ end
41
45
  end
42
46
 
43
- def shell_option(flag, val = nil, escape: true, quote: true, force: true)
47
+ def shell_option(flag, val = nil, escape: true, quote: true, force: true, double: false, override: false,
48
+ merge: false)
44
49
  flag = flag.to_s
50
+ if flag =~ /^(["'])(.+)\1$/
51
+ double = $1 == '"'
52
+ flag = $2
53
+ escape = false
54
+ override = true
55
+ end
45
56
  if flag[0] == '-'
46
57
  b = flag[1] == '-' ? '=' : ' '
58
+ elsif flag.size == 1
59
+ a = '-'
60
+ b = merge ? '' : ' '
47
61
  else
48
- a, b = flag.size == 1 ? ['-', ' '] : ['--', '=']
62
+ a = '--'
63
+ b = '='
49
64
  end
50
65
  "#{a}#{flag}#{if val
51
66
  "#{b}#{if escape
52
- shell_escape(val, quote: quote)
67
+ shell_escape(val, quote: quote, double: double, override: override)
53
68
  else
54
- quote ? shell_quote(val, force: force) : val
69
+ quote ? shell_quote(val, force: force, double: double, override: override) : val
55
70
  end}"
56
71
  end}"
57
72
  end
58
73
 
59
- def fill_option(val)
60
- return "-#{val}" if val =~ /\A[a-z](?:\d*)\z/i
74
+ def shell_split(val, escape: true, quote: false, join: nil)
75
+ ret = Shellwords.split(val)
76
+ return ret if join == false
61
77
 
62
- shell_escape(val.start_with?('-') ? val : "--#{val}")
63
- end
78
+ ret = ret.map { |opt| shell_escape(opt, quote: quote) } if escape
79
+ return ret unless join
64
80
 
65
- def quote_option(flag, val)
66
- shell_option(flag, val, escape: false)
81
+ ret.join(join.is_a?(::String) ? join : ' ')
67
82
  end
68
83
 
69
- def basic_option(flag, val)
70
- shell_option(flag, val, escape: false, force: false)
71
- end
84
+ def fill_option(val, double: false)
85
+ return "-#{val}" if val.match?(/^[a-z]\d*$/i)
72
86
 
73
- def single_quote(val)
74
- val.gsub("'", "'\\\\''")
87
+ shell_escape(val.start_with?('-') ? val : "--#{val}", double: double)
75
88
  end
76
89
 
77
- def double_quote(val)
78
- val.gsub(/(?<!\\)"/, '\\"')
90
+ def quote_option(flag, val, double: false)
91
+ shell_option(flag, val, escape: false, double: double)
79
92
  end
80
93
 
81
- def split_escape(val, char: ',')
82
- val.split(/\s*(?<!\\)#{char}\s*/o)
94
+ def basic_option(flag, val, merge: false)
95
+ shell_option(flag, val, escape: false, force: false, merge: merge)
83
96
  end
84
97
  end
85
98
  end
@@ -8,6 +8,10 @@ module Squared
8
8
  module Utils
9
9
  module_function
10
10
 
11
+ def split_escape(val, char: ',')
12
+ val.split(/\s*(?<!\\)#{char}\s*/o)
13
+ end
14
+
11
15
  def task_invoke(*cmd, args: [], exception: true, warning: true)
12
16
  cmd.each { |name| Rake::Task[name].invoke(*args) }
13
17
  rescue StandardError => e
@@ -31,8 +35,57 @@ module Squared
31
35
  Rake::Task.tasks.any? do |obj|
32
36
  next unless obj.already_invoked
33
37
 
34
- args.any? { |val| val.is_a?(::Regexp) ? obj.name =~ val : val == obj.name }
38
+ args.any? { |val| val.is_a?(::Regexp) ? obj.name.match?(val) : val == obj.name }
39
+ end
40
+ end
41
+
42
+ def time_format(epoch, clock: false, pass: [])
43
+ ss = 1000
44
+ mm = 60 * ss
45
+ hh = 60 * mm
46
+ dd = 24 * hh
47
+ hm = pass.include?('s')
48
+ time = []
49
+ if !clock && (d = epoch / dd) > 0
50
+ time << "#{d}d"
51
+ epoch -= d * dd
52
+ end
53
+ if (h = epoch / hh) > 0
54
+ time << (clock ? h.to_s : "#{h}h")
55
+ epoch -= h * hh
35
56
  end
57
+ if (m = epoch / mm) > 0
58
+ time << (clock ? m.to_s.rjust(2, '0') : "#{m}m")
59
+ epoch -= m * mm
60
+ elsif clock
61
+ time << '00'
62
+ end
63
+ unless hm
64
+ if (s = epoch / ss) > 0
65
+ time << (clock ? s.to_s.rjust(2, '0') : "#{s}s")
66
+ epoch -= s * ss
67
+ elsif clock
68
+ time << '00'
69
+ end
70
+ end
71
+ if clock
72
+ time.join(':')
73
+ else
74
+ time << "#{epoch}ms" unless hm || pass.include?('ms')
75
+ time.join(' ')
76
+ end
77
+ end
78
+
79
+ def time_offset(val = nil)
80
+ val = DateTime.parse(val) if val.is_a?(::String)
81
+ cur = DateTime.now
82
+ ret = 0
83
+ if (r = /^([+-])(\d+):(\d+):(\d+)$/.match((val || cur).strftime('%::z')))
84
+ ret += (r[1] == '+' ? -1 : 1) * ((r[2].to_i * 60 * 60) + (r[3].to_i * 60) + r[4].to_i) * 1000
85
+ end
86
+ return ret unless val
87
+
88
+ (cur.strftime('%Q').to_i + time_offset) - (val.strftime('%Q').to_i + ret)
36
89
  end
37
90
 
38
91
  def env(key, default = nil, suffix: nil, strict: false, equals: nil, ignore: nil)
@@ -90,7 +90,7 @@ module Squared
90
90
  @required = true
91
91
  project ? [project, 'not found'] : ['name', 'missing']
92
92
  end
93
- warn log_message(Logger::WARN, msg, subject: self.class, hint: hint)
93
+ warn log_message(Logger::WARN, msg, subject: self.class, hint: hint, pass: true)
94
94
  end
95
95
 
96
96
  def build
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Squared
4
- VERSION = '0.3.4'
4
+ VERSION = '0.4.0'
5
5
  end
@@ -173,7 +173,7 @@ module Squared
173
173
  when Symbol
174
174
  @ref = val
175
175
  else
176
- raise_error('group{Symbol} | ref{String}', hint: 'missing') if block_given?
176
+ raise_error 'missing group or ref' if block_given?
177
177
  end
178
178
  if block_given?
179
179
  instance_eval(&blk)
@@ -357,7 +357,7 @@ module Squared
357
357
  }
358
358
  data.each do |key, val|
359
359
  key = key.to_s
360
- if /\A(\\A|\^)/ =~ key || /(\\z|\$)\z/ =~ key
360
+ if key.match?(/\A(\\A|\^)/) || key.match?(/(\\z|\$)\z/)
361
361
  @describe[:replace] << [Regexp.new(key), val]
362
362
  else
363
363
  @describe[val.is_a?(Regexp) ? :pattern : :alias][key.to_s] = val
@@ -415,15 +415,14 @@ module Squared
415
415
  val = name || task_join(*args)
416
416
  found = false
417
417
  replace = lambda do |data, out|
418
- if (index = data.size) > 0
419
- data.to_a.reverse_each { |group| out.sub!("%#{index -= 1}", group) }
420
- end
418
+ index = data.size
419
+ data.to_a.reverse_each { |group| out.sub!("%#{index -= 1}", group) }
421
420
  out
422
421
  end
423
- @describe[:replace].each do |pat, key|
424
- next unless (data = pat.match(val))
422
+ @describe[:replace].each do |pat, tmpl|
423
+ next unless val =~ pat
425
424
 
426
- val = replace.(data, key.dup)
425
+ val = replace.($~, tmpl.dup)
427
426
  found = true
428
427
  end
429
428
  if (out = @describe[:alias][val])
@@ -431,14 +430,14 @@ module Squared
431
430
  found = true
432
431
  else
433
432
  @describe[:pattern].each do |key, pat|
434
- next unless (data = pat.match(val))
433
+ next unless val =~ pat
435
434
 
436
- val = replace.(data, key.dup)
435
+ val = replace.($~, key.dup)
437
436
  found = true
438
437
  break
439
438
  end
440
439
  end
441
- args = Shell.split_escape(val, char: ':').map! { |s| s.gsub('\\:', ':') } if found
440
+ args = split_escape(val, char: ':').map! { |s| s.gsub('\\:', ':') } if found
442
441
  end
443
442
  desc message(*args, **kwargs)
444
443
  end
@@ -564,7 +563,7 @@ module Squared
564
563
 
565
564
  key = task_join(task_localname(obj.name), key)
566
565
  end
567
- @pass[:pattern].any? { |item| item.is_a?(Regexp) ? key =~ item : key == item }
566
+ @pass[:pattern].any? { |item| item.is_a?(Regexp) ? key.to_s.match?(item) : key == item }
568
567
  end
569
568
 
570
569
  def task_defined?(*key)
@@ -587,6 +586,10 @@ module Squared
587
586
  Rake::Win32.windows?
588
587
  end
589
588
 
589
+ def docker?
590
+ File.exist?('/.dockerenv')
591
+ end
592
+
590
593
  def rootpath(*args)
591
594
  root.join(*args)
592
595
  end
@@ -693,7 +696,7 @@ module Squared
693
696
  end
694
697
  return false if state == :prod && data[:dev] == true && data[:global]
695
698
 
696
- target && pat.is_a?(Regexp) ? as_a(target).any? { |val| val =~ pat } : pat == true
699
+ target && pat.is_a?(Regexp) ? as_a(target).any? { |val| val.match?(pat) } : pat == true
697
700
  end
698
701
 
699
702
  def scriptobj