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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +67 -2
- data/README.md +13 -2
- data/README.ruby.md +168 -88
- data/lib/squared/app.rb +1 -0
- data/lib/squared/common/base.rb +6 -1
- data/lib/squared/common/class.rb +1 -1
- data/lib/squared/common/format.rb +24 -12
- data/lib/squared/common/prompt.rb +2 -2
- data/lib/squared/common/shell.rb +52 -39
- data/lib/squared/common/utils.rb +54 -1
- data/lib/squared/config.rb +1 -1
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/application.rb +16 -13
- data/lib/squared/workspace/project/base.rb +429 -123
- data/lib/squared/workspace/project/docker.rb +572 -0
- data/lib/squared/workspace/project/git.rb +405 -157
- data/lib/squared/workspace/project/node.rb +51 -51
- data/lib/squared/workspace/project/python.rb +115 -24
- data/lib/squared/workspace/project/ruby.rb +33 -34
- data/lib/squared/workspace/project.rb +7 -1
- data/lib/squared/workspace/repo.rb +9 -4
- data/lib/squared/workspace/series.rb +1 -1
- metadata +2 -1
@@ -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, :
|
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
|
-
|
231
|
-
|
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 = "
|
248
|
+
s = "#{b0} #{s} #{b0}"
|
237
249
|
if border
|
238
|
-
s = sub_style(s, pat: /\A(
|
239
|
-
s = sub_style(s, pat: /\A(.+)(
|
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 <<
|
255
|
+
out << draw.(b2, b3)
|
244
256
|
if title
|
245
257
|
out += title.map { |t| pr.(t) }
|
246
|
-
out <<
|
258
|
+
out << draw.(b6, b7)
|
247
259
|
end
|
248
260
|
lines.each { |line| out << pr.(line) }
|
249
|
-
out <<
|
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 =
|
12
|
-
cancel =
|
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))
|
data/lib/squared/common/shell.rb
CHANGED
@@ -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 (
|
13
|
-
return val if !
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
60
|
-
|
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
|
-
|
63
|
-
|
78
|
+
ret = ret.map { |opt| shell_escape(opt, quote: quote) } if escape
|
79
|
+
return ret unless join
|
64
80
|
|
65
|
-
|
66
|
-
shell_option(flag, val, escape: false)
|
81
|
+
ret.join(join.is_a?(::String) ? join : ' ')
|
67
82
|
end
|
68
83
|
|
69
|
-
def
|
70
|
-
|
71
|
-
end
|
84
|
+
def fill_option(val, double: false)
|
85
|
+
return "-#{val}" if val.match?(/^[a-z]\d*$/i)
|
72
86
|
|
73
|
-
|
74
|
-
val.gsub("'", "'\\\\''")
|
87
|
+
shell_escape(val.start_with?('-') ? val : "--#{val}", double: double)
|
75
88
|
end
|
76
89
|
|
77
|
-
def
|
78
|
-
|
90
|
+
def quote_option(flag, val, double: false)
|
91
|
+
shell_option(flag, val, escape: false, double: double)
|
79
92
|
end
|
80
93
|
|
81
|
-
def
|
82
|
-
val
|
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
|
data/lib/squared/common/utils.rb
CHANGED
@@ -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
|
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)
|
data/lib/squared/config.rb
CHANGED
@@ -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
|
data/lib/squared/version.rb
CHANGED
@@ -173,7 +173,7 @@ module Squared
|
|
173
173
|
when Symbol
|
174
174
|
@ref = val
|
175
175
|
else
|
176
|
-
raise_error
|
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|\^)/
|
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
|
-
|
419
|
-
|
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,
|
424
|
-
next unless
|
422
|
+
@describe[:replace].each do |pat, tmpl|
|
423
|
+
next unless val =~ pat
|
425
424
|
|
426
|
-
val = replace.(
|
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
|
433
|
+
next unless val =~ pat
|
435
434
|
|
436
|
-
val = replace.(
|
435
|
+
val = replace.($~, key.dup)
|
437
436
|
found = true
|
438
437
|
break
|
439
438
|
end
|
440
439
|
end
|
441
|
-
args =
|
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
|
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
|
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
|