squared 0.4.36 → 0.5.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 +64 -529
- data/README.md +1283 -663
- data/README.ruby.md +722 -0
- data/lib/squared/common/base.rb +8 -9
- data/lib/squared/common/format.rb +26 -39
- data/lib/squared/common/prompt.rb +46 -51
- data/lib/squared/common/shell.rb +50 -70
- data/lib/squared/common/system.rb +34 -37
- data/lib/squared/common/utils.rb +3 -28
- data/lib/squared/common.rb +2 -1
- data/lib/squared/config.rb +30 -33
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/application.rb +82 -122
- data/lib/squared/workspace/project/base.rb +432 -578
- data/lib/squared/workspace/project/docker.rb +186 -214
- data/lib/squared/workspace/project/git.rb +368 -512
- data/lib/squared/workspace/project/node.rb +195 -315
- data/lib/squared/workspace/project/python.rb +125 -355
- data/lib/squared/workspace/project/ruby.rb +258 -340
- data/lib/squared/workspace/project/support/class.rb +92 -313
- data/lib/squared/workspace/project.rb +0 -10
- data/lib/squared/workspace/repo.rb +58 -99
- data/lib/squared/workspace/series.rb +41 -47
- data/lib/squared/workspace/support/data.rb +3 -2
- data/lib/squared/workspace/support.rb +0 -1
- data/lib/squared/workspace.rb +3 -5
- data/squared.gemspec +5 -5
- metadata +7 -8
- data/lib/squared/common/class.rb +0 -186
- data/lib/squared/workspace/support/base.rb +0 -32
data/lib/squared/common/base.rb
CHANGED
|
@@ -63,7 +63,6 @@ module Squared
|
|
|
63
63
|
hash: %i[green black!],
|
|
64
64
|
array: %i[blue black!],
|
|
65
65
|
number: [:magenta],
|
|
66
|
-
boolean: [:magenta],
|
|
67
66
|
undefined: %i[red italic]
|
|
68
67
|
},
|
|
69
68
|
logger: {
|
|
@@ -94,28 +93,28 @@ module Squared
|
|
|
94
93
|
PATH.freeze
|
|
95
94
|
ARG.freeze
|
|
96
95
|
VAR.each_value(&:freeze)
|
|
97
|
-
VAR[:theme].each_value
|
|
96
|
+
VAR[:theme].each_value(&:freeze)
|
|
98
97
|
VAR.freeze
|
|
99
98
|
end
|
|
100
99
|
|
|
101
100
|
module_function
|
|
102
101
|
|
|
103
|
-
def as_a(obj, meth
|
|
102
|
+
def as_a(obj, *meth, flat: nil, compact: false, &blk)
|
|
104
103
|
return [] if obj.nil?
|
|
105
104
|
|
|
106
105
|
unless obj.is_a?(::Array)
|
|
107
|
-
obj = if obj.respond_to?(:
|
|
108
|
-
obj.to_ary
|
|
109
|
-
elsif obj.respond_to?(:to_a) && !obj.is_a?(::Hash) && (val = obj.to_a).is_a?(::Array)
|
|
106
|
+
obj = if obj.respond_to?(:to_a) && !obj.is_a?(::Hash) && (val = obj.to_a).is_a?(::Array)
|
|
110
107
|
val
|
|
111
108
|
else
|
|
112
109
|
[obj]
|
|
113
110
|
end
|
|
114
111
|
end
|
|
115
|
-
obj = flat.is_a?(::Numeric) ?
|
|
112
|
+
obj = obj.flatten(flat.is_a?(::Numeric) ? flat : nil) if flat
|
|
116
113
|
obj = obj.compact if compact
|
|
117
|
-
obj = obj.map(&meth)
|
|
118
|
-
|
|
114
|
+
obj = obj.map(&meth.shift) until meth.empty?
|
|
115
|
+
return obj unless block_given?
|
|
116
|
+
|
|
117
|
+
obj.select(&blk)
|
|
119
118
|
end
|
|
120
119
|
end
|
|
121
120
|
end
|
|
@@ -29,19 +29,13 @@ module Squared
|
|
|
29
29
|
bright_white!: '107'
|
|
30
30
|
}.freeze
|
|
31
31
|
BOX_GRAPH = ['│', '─', '├', '└', '┬'].freeze
|
|
32
|
-
BOX_BORDER = ['│', '─', '
|
|
33
|
-
if ENV['TERM']&.end_with?('256color')
|
|
34
|
-
val.slice!(2, 4)
|
|
35
|
-
val.insert(2, '╭', '╮', '╯', '╰')
|
|
36
|
-
end
|
|
37
|
-
val.freeze
|
|
38
|
-
end
|
|
32
|
+
BOX_BORDER = ['│', '─', '╭', '╮', '╯', '╰', '├', '┤', '┬', '┴'].freeze
|
|
39
33
|
TEXT_STYLE = [:bold, :dim, :italic, :underline, :blinking, nil, :inverse, :hidden, :strikethrough].freeze
|
|
40
34
|
private_constant :AIX_TERM, :BOX_GRAPH, :BOX_BORDER, :TEXT_STYLE
|
|
41
35
|
|
|
42
36
|
def enable_aixterm
|
|
43
37
|
unless (colors = __get__(:colors)).frozen?
|
|
44
|
-
colors.
|
|
38
|
+
colors.update(AIX_TERM)
|
|
45
39
|
end
|
|
46
40
|
self
|
|
47
41
|
end
|
|
@@ -67,8 +61,7 @@ module Squared
|
|
|
67
61
|
end
|
|
68
62
|
wrap = ->(s, n) { "\x1B[#{n.join(';')}m#{s}\x1B[0m" }
|
|
69
63
|
code = []
|
|
70
|
-
args.
|
|
71
|
-
args.concat(Array(styles)).flatten.each_with_index do |type, i|
|
|
64
|
+
args.concat(as_a(styles)).flatten.each_with_index do |type, i|
|
|
72
65
|
next unless type
|
|
73
66
|
|
|
74
67
|
if index == -1
|
|
@@ -109,7 +102,7 @@ module Squared
|
|
|
109
102
|
ret = wrap.call(ret, code) unless code.empty?
|
|
110
103
|
return ret unless data
|
|
111
104
|
|
|
112
|
-
out =
|
|
105
|
+
out = ''.dup
|
|
113
106
|
data.to_a.each_with_index do |group, i|
|
|
114
107
|
next if i == 0
|
|
115
108
|
|
|
@@ -142,11 +135,11 @@ module Squared
|
|
|
142
135
|
def apply_style(data, key, args, empty: true)
|
|
143
136
|
return if data.is_a?(::Symbol) && (data = __get__(:theme)[data]).nil?
|
|
144
137
|
|
|
145
|
-
set = ->(k, v) { data[k
|
|
138
|
+
set = ->(k, v) { data[k] = check_style(v, empty: empty) }
|
|
146
139
|
if key.is_a?(::Hash)
|
|
147
140
|
key.each { |k, v| set.call(k, v || args) }
|
|
148
141
|
else
|
|
149
|
-
set.call(key, args)
|
|
142
|
+
set.call(key.to_sym, args)
|
|
150
143
|
end
|
|
151
144
|
end
|
|
152
145
|
|
|
@@ -158,8 +151,7 @@ module Squared
|
|
|
158
151
|
when Logger::WARN then :warn
|
|
159
152
|
when Logger::ERROR then :error
|
|
160
153
|
when Logger::FATAL then :fatal
|
|
161
|
-
else :unknown
|
|
162
|
-
end
|
|
154
|
+
else :unknown end
|
|
163
155
|
else
|
|
164
156
|
level.to_s.downcase.to_sym
|
|
165
157
|
end
|
|
@@ -180,30 +172,26 @@ module Squared
|
|
|
180
172
|
if level.is_a?(::Numeric)
|
|
181
173
|
if append && respond_to?(:log)
|
|
182
174
|
ref = log rescue nil
|
|
183
|
-
ref.add(level, message(subject, *args, hint: hint, space: ', ')) if ref.is_a?(
|
|
175
|
+
ref.add(level, message(subject, *args, hint: hint, space: ', ')) if ref.is_a?(Logger)
|
|
184
176
|
end
|
|
185
|
-
return false
|
|
177
|
+
return false if !pass && level < ARG[:LEVEL]
|
|
186
178
|
end
|
|
187
|
-
if
|
|
179
|
+
if (args.size > 1 && !hint) || hint == false
|
|
188
180
|
title = log_title(level, color: false)
|
|
189
|
-
if color
|
|
190
|
-
sub = [{ pat: /\A(#{Regexp.escape(title)})(.*)\z/m, styles: __get__(:theme)[:logger][log_sym(level)] }]
|
|
191
|
-
end
|
|
181
|
+
sub = [pat: /\A(#{Regexp.escape(title)})(.*)\z/m, styles: __get__(:theme)[:logger][log_sym(level)]] if color
|
|
192
182
|
emphasize(args, title: title + (subject ? " #{subject}" : ''), sub: sub, pipe: -1)
|
|
193
183
|
else
|
|
194
184
|
msg = [log_title(level, color: color)]
|
|
195
|
-
if subject
|
|
196
|
-
msg << (color ? sub_style(subject.to_s, (@theme.is_a?(::Hash) && @theme[:subject]) || :bold) : subject)
|
|
197
|
-
end
|
|
185
|
+
msg << (color ? sub_style(subject, styles: (@theme && @theme[:subject]) || :bold) : subject) if subject
|
|
198
186
|
msg << args.shift if msg.size == 1
|
|
199
187
|
message(msg.join(' '), *args, hint: hint)
|
|
200
188
|
end
|
|
201
189
|
end
|
|
202
190
|
|
|
203
|
-
def
|
|
191
|
+
def puts_oe(*args, pipe: 1)
|
|
204
192
|
return if args.first == false && args.size == 1
|
|
205
193
|
|
|
206
|
-
if pipe.is_a?(
|
|
194
|
+
if pipe.is_a?(Pathname)
|
|
207
195
|
begin
|
|
208
196
|
File.open(pipe, 'a') do |f|
|
|
209
197
|
br = File::SEPARATOR == '\\' ? "\r\n" : "\n"
|
|
@@ -217,30 +205,29 @@ module Squared
|
|
|
217
205
|
(pipe == 2 ? $stderr : $stdout).puts(*args)
|
|
218
206
|
end
|
|
219
207
|
|
|
220
|
-
alias puts_oe log_console
|
|
221
|
-
|
|
222
208
|
module_function
|
|
223
209
|
|
|
224
210
|
def message(*args, hint: nil, empty: false, space: ARG[:SPACE])
|
|
225
|
-
(empty ? args.reject { |val| val.nil? ||
|
|
226
|
-
.join(space) + (hint ? " (#{hint})" : '')
|
|
211
|
+
(empty ? args.reject { |val| val.nil? || val.empty? } : args).join(space) + (hint ? " (#{hint})" : '')
|
|
227
212
|
end
|
|
228
213
|
|
|
229
214
|
def emphasize(val, title: nil, footer: nil, right: false, cols: nil, sub: nil, pipe: nil,
|
|
230
|
-
border: @theme
|
|
215
|
+
border: @theme && @theme[:border])
|
|
231
216
|
n = 0
|
|
232
|
-
max = ->(
|
|
233
|
-
set =
|
|
217
|
+
max = ->(v) { n = [n, v.max_by(&:size).size].max }
|
|
218
|
+
set = lambda do |v|
|
|
219
|
+
ret = as_a(v, :to_s)
|
|
220
|
+
max.call(ret)
|
|
221
|
+
ret
|
|
222
|
+
end
|
|
234
223
|
title &&= set.call(title)
|
|
235
224
|
footer &&= set.call(footer)
|
|
236
225
|
if val.is_a?(::Array)
|
|
237
226
|
lines = val.map(&:to_s)
|
|
238
227
|
else
|
|
239
228
|
lines = val.to_s.lines(chomp: true)
|
|
240
|
-
lines[0] = "#{val.class}: #{lines.first}" if (err = val.is_a?(
|
|
229
|
+
lines[0] = "#{val.class}: #{lines.first}" if (err = val.is_a?(StandardError))
|
|
241
230
|
end
|
|
242
|
-
return if lines.empty?
|
|
243
|
-
|
|
244
231
|
n = cols || max.call(lines)
|
|
245
232
|
if $stdout.tty?
|
|
246
233
|
require 'io/console'
|
|
@@ -259,8 +246,8 @@ module Squared
|
|
|
259
246
|
sub.each { |h| s = sub_style(s, **h) }
|
|
260
247
|
s = "#{b0} #{s} #{b0}"
|
|
261
248
|
if border
|
|
262
|
-
s = sub_style(s, pat: /\A(#{Regexp.escape(b0)})(.+)\z/
|
|
263
|
-
s = sub_style(s, pat: /\A(.+)(#{Regexp.escape(b0)})\z/
|
|
249
|
+
s = sub_style(s, pat: /\A(#{Regexp.escape(b0)})(.+)\z/m, styles: border)
|
|
250
|
+
s = sub_style(s, pat: /\A(.+)(#{Regexp.escape(b0)})\z/m, styles: border, index: 2)
|
|
264
251
|
end
|
|
265
252
|
s
|
|
266
253
|
end
|
|
@@ -294,7 +281,7 @@ module Squared
|
|
|
294
281
|
else
|
|
295
282
|
pipe = $stdout unless pipe.respond_to?(:puts)
|
|
296
283
|
end
|
|
297
|
-
pipe.puts
|
|
284
|
+
pipe.puts out
|
|
298
285
|
else
|
|
299
286
|
err ? warn(out) : puts(out)
|
|
300
287
|
end
|
|
@@ -11,24 +11,22 @@ module Squared
|
|
|
11
11
|
agree = /^#{Regexp.escape(agree)}$/i if agree.is_a?(::String)
|
|
12
12
|
cancel = /^#{Regexp.escape(cancel)}$/i if cancel.is_a?(::String)
|
|
13
13
|
Timeout.timeout(timeout) do
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return false
|
|
22
|
-
end
|
|
23
|
-
attempts -= 1
|
|
24
|
-
exit 1 unless attempts > 0
|
|
14
|
+
while (ch = Readline.readline(msg))
|
|
15
|
+
ch = ch.chomp
|
|
16
|
+
case (ch.empty? ? default : ch)
|
|
17
|
+
when agree
|
|
18
|
+
return true
|
|
19
|
+
when cancel
|
|
20
|
+
return false
|
|
25
21
|
end
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
exit 0
|
|
29
|
-
else
|
|
30
|
-
false
|
|
22
|
+
attempts -= 1
|
|
23
|
+
exit 1 unless attempts > 0
|
|
31
24
|
end
|
|
25
|
+
rescue Interrupt
|
|
26
|
+
puts
|
|
27
|
+
exit 0
|
|
28
|
+
else
|
|
29
|
+
false
|
|
32
30
|
end
|
|
33
31
|
end
|
|
34
32
|
|
|
@@ -37,49 +35,50 @@ module Squared
|
|
|
37
35
|
require 'readline'
|
|
38
36
|
require 'timeout'
|
|
39
37
|
if list
|
|
40
|
-
grep &&=
|
|
38
|
+
grep &&= (grep.is_a?(::Enumerable) ? grep : [grep]).map { |val| Regexp.new(val) }
|
|
41
39
|
items = []
|
|
42
40
|
list.each do |val|
|
|
43
41
|
next if grep&.none? { |pat| pat.match?(line) }
|
|
44
42
|
|
|
45
|
-
items << val.
|
|
43
|
+
items << val.chomp
|
|
46
44
|
puts "#{items.size.to_s.rjust(2)}. #{val}"
|
|
47
45
|
end
|
|
48
46
|
max = items.size
|
|
49
47
|
raise_error 'empty selection list' if max == 0
|
|
50
|
-
min =
|
|
48
|
+
min = [min, max].min
|
|
51
49
|
if auto
|
|
52
|
-
msg = "#{msg}: [
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
msg = "#{msg}: [1-#{max}#{if multiple
|
|
51
|
+
"|,#{multiple.is_a?(Numeric) ? "{#{multiple}}" : ''}"
|
|
52
|
+
end}] "
|
|
55
53
|
end
|
|
56
54
|
end
|
|
57
55
|
valid = ->(s) { s.match?(/^-?\d+$/) && s.to_i.between?(min, max) }
|
|
58
56
|
Timeout.timeout(timeout) do
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
elsif valid.call(ch)
|
|
68
|
-
return items ? items[ch.to_i - 1] : ch.to_i
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
attempts -= 1
|
|
72
|
-
next if attempts > 0
|
|
57
|
+
while (ch = Readline.readline(msg))
|
|
58
|
+
unless (ch = ch.strip).empty?
|
|
59
|
+
if multiple
|
|
60
|
+
a = ch.split(/\s*,\s*/)
|
|
61
|
+
b = a.select { |s| valid.call(s) }.map!(&:to_i).sort
|
|
62
|
+
next unless a.size == b.size
|
|
63
|
+
return b unless items
|
|
64
|
+
next if multiple.is_a?(::Numeric) && multiple != b.size
|
|
73
65
|
|
|
74
|
-
|
|
75
|
-
|
|
66
|
+
return b.map! { |i| items[i - 1] }
|
|
67
|
+
elsif valid.call(ch)
|
|
68
|
+
return items ? items[ch.to_i - 1] : ch.to_i
|
|
69
|
+
end
|
|
76
70
|
end
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
71
|
+
attempts -= 1
|
|
72
|
+
next if attempts > 0
|
|
73
|
+
break unless force
|
|
74
|
+
|
|
75
|
+
exit 1
|
|
82
76
|
end
|
|
77
|
+
rescue Interrupt
|
|
78
|
+
puts
|
|
79
|
+
exit 0
|
|
80
|
+
else
|
|
81
|
+
multiple ? [] : nil
|
|
83
82
|
end
|
|
84
83
|
end
|
|
85
84
|
|
|
@@ -94,23 +93,19 @@ module Squared
|
|
|
94
93
|
elsif block_given?
|
|
95
94
|
Readline.readmultiline(msg, history, &blk)
|
|
96
95
|
else
|
|
97
|
-
Readline.readmultiline(msg, history)
|
|
98
|
-
next if line.strip.empty?
|
|
99
|
-
|
|
100
|
-
multiline.any? { |val| line.split.last.end_with?(val.to_s) }
|
|
101
|
-
end
|
|
96
|
+
Readline.readmultiline(msg, history) { |line| multiline.any? { |val| line.split.last.end_with?(val) } }
|
|
102
97
|
end
|
|
103
98
|
end
|
|
104
99
|
case force
|
|
105
100
|
when ::TrueClass, ::FalseClass
|
|
106
101
|
msg = "#{msg} %s " % if multiline
|
|
107
|
-
multiline.is_a?(::Enumerable) ? "{#{multiline.
|
|
102
|
+
multiline.is_a?(::Enumerable) ? "{#{multiline.join('|')}}" : multiline
|
|
108
103
|
else
|
|
109
104
|
"(#{force ? 'required' : 'optional'}):"
|
|
110
105
|
end
|
|
111
106
|
ret = (prompt.call || '').strip
|
|
112
|
-
multiline.each { |val| break if ret.delete_suffix!(val
|
|
113
|
-
|
|
107
|
+
multiline.each { |val| break if ret.delete_suffix!(val) } if multiline.is_a?(::Enumerable)
|
|
108
|
+
raise_error 'user cancelled' if force && ret.empty?
|
|
114
109
|
ret
|
|
115
110
|
else
|
|
116
111
|
prompt.call
|
data/lib/squared/common/shell.rb
CHANGED
|
@@ -6,31 +6,28 @@ require 'rake'
|
|
|
6
6
|
module Squared
|
|
7
7
|
module Common
|
|
8
8
|
module Shell
|
|
9
|
-
QUOTE_VALUE = /\A(["'])(.*)\1\z/m.freeze
|
|
10
|
-
private_constant :QUOTE_VALUE
|
|
11
|
-
|
|
12
9
|
module_function
|
|
13
10
|
|
|
14
11
|
def shell_escape(val, quote: false, force: false, double: false, option: false, override: false)
|
|
15
|
-
if (r = /\A(--?)([
|
|
16
|
-
if (data = r[2].match(
|
|
12
|
+
if (r = /\A(--?)([^= ]+)((=|\s+)(["'])?(?(5)(.*)\5|(.*)))?\z/m.match(val = val.to_s))
|
|
13
|
+
if (data = r[2].match(/\A(["'])(.+)\1\z/))
|
|
17
14
|
double = data[1] == '"'
|
|
18
15
|
override = true
|
|
19
16
|
elsif !r[3] || r[6]
|
|
20
17
|
return val
|
|
21
18
|
end
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
r[1] + (data ? data[2] : r[2]) + r[4] + shell_quote(opt,
|
|
32
|
-
elsif option && val =~ /\A(
|
|
33
|
-
return val if $2.match?(
|
|
19
|
+
if r[7].match?(/\A["']/)
|
|
20
|
+
opt = "#{r[7]}#{r[7][0]}"
|
|
21
|
+
elsif r[7].match?(/["']\z/)
|
|
22
|
+
opt = "#{r[7][-1]}#{r[7]}"
|
|
23
|
+
else
|
|
24
|
+
return val unless r[7].match?(/\s/)
|
|
25
|
+
|
|
26
|
+
opt = r[7]
|
|
27
|
+
end
|
|
28
|
+
r[1] + (data ? data[2] : r[2]) + r[4] + shell_quote(opt, double: double, force: force, override: override)
|
|
29
|
+
elsif option && val =~ /\A([^=]+)=(.+)\z/m
|
|
30
|
+
return val if $2.match?(/\A(["']).+\1\z/m)
|
|
34
31
|
|
|
35
32
|
"#{$1}=%s" % if $2.include?(' ')
|
|
36
33
|
shell_quote($2, option: false)
|
|
@@ -38,98 +35,81 @@ module Squared
|
|
|
38
35
|
Rake::Win32.windows? ? $2 : Shellwords.escape($2)
|
|
39
36
|
end
|
|
40
37
|
elsif Rake::Win32.windows?
|
|
41
|
-
quote ? shell_quote(val,
|
|
42
|
-
elsif val.empty?
|
|
43
|
-
''
|
|
38
|
+
quote ? shell_quote(val, double: double, force: force) : val
|
|
44
39
|
else
|
|
45
|
-
Shellwords.escape(val)
|
|
40
|
+
val.empty? ? '' : Shellwords.escape(val)
|
|
46
41
|
end
|
|
47
42
|
end
|
|
48
43
|
|
|
49
|
-
def shell_quote(val, option: true, force: true, double: false,
|
|
44
|
+
def shell_quote(val, option: true, force: true, double: false, override: false)
|
|
50
45
|
val = val.to_s
|
|
51
46
|
return val if (!force && !val.include?(' ')) || val.empty?
|
|
52
47
|
|
|
53
|
-
if option
|
|
54
|
-
|
|
55
|
-
return val if val.match?(pat)
|
|
48
|
+
if option && val.match?(/(?:\A|\A[^=\s]+(?:=|\s+)|#{Rake::Win32.windows? ? '[\\\/]' : '\/'})(["']).+\1\z/m)
|
|
49
|
+
return val
|
|
56
50
|
end
|
|
57
|
-
q = ->(s) { s.gsub("'\\\\''", "'") }
|
|
58
|
-
if val =~ QUOTE_VALUE
|
|
59
|
-
return val if $1 == '"' && Rake::Win32.windows? && val.match?(/(?:[#{File::SEPARATOR} ]|\\")/o)
|
|
60
51
|
|
|
61
|
-
base = $2 unless preserve
|
|
62
|
-
end
|
|
63
52
|
if double || Rake::Win32.windows? || (ARG[:QUOTE] == '"' && !override)
|
|
64
|
-
"\"#{
|
|
53
|
+
"\"#{val.gsub(/(?<!\\)"/, '\\"')}\""
|
|
65
54
|
else
|
|
66
|
-
|
|
55
|
+
"'#{val.gsub("'", "'\\\\''")}'"
|
|
67
56
|
end
|
|
68
57
|
end
|
|
69
58
|
|
|
70
59
|
def shell_option(flag, val = nil, escape: true, quote: true, option: true, force: true, double: false,
|
|
71
60
|
merge: false, override: false)
|
|
72
61
|
flag = flag.to_s
|
|
73
|
-
if flag =~
|
|
62
|
+
if flag =~ /\A(["'])(.+)\1\z/
|
|
74
63
|
double = $1 == '"'
|
|
75
64
|
flag = $2
|
|
76
65
|
escape = false
|
|
77
66
|
override = true
|
|
78
67
|
end
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
elsif quote
|
|
98
|
-
shell_quote(val, option: option, force: force, double: double, override: override)
|
|
99
|
-
else
|
|
100
|
-
val
|
|
101
|
-
end}"
|
|
102
|
-
end}"
|
|
68
|
+
if flag[0] == '-'
|
|
69
|
+
b = flag[1] == '-' ? '=' : ' '
|
|
70
|
+
elsif flag.size == 1
|
|
71
|
+
a = '-'
|
|
72
|
+
b = merge ? '' : ' '
|
|
73
|
+
else
|
|
74
|
+
a = '--'
|
|
75
|
+
b = '='
|
|
76
|
+
end
|
|
77
|
+
"#{a}#{flag}#{if val
|
|
78
|
+
"#{b}#{if escape
|
|
79
|
+
shell_escape(val, quote: quote, double: double, override: override)
|
|
80
|
+
elsif quote
|
|
81
|
+
shell_quote(val, option: option, force: force, double: double, override: override)
|
|
82
|
+
else
|
|
83
|
+
val
|
|
84
|
+
end}"
|
|
85
|
+
end}"
|
|
103
86
|
end
|
|
104
87
|
|
|
105
|
-
def shell_split(val,
|
|
106
|
-
ret = val.shellsplit
|
|
88
|
+
def shell_split(val, join: nil, **kwargs)
|
|
89
|
+
ret = val.shellsplit
|
|
90
|
+
ret.map! { |opt| shell_escape(opt, double: true, option: true, **kwargs) }
|
|
107
91
|
return ret unless join
|
|
108
92
|
|
|
109
93
|
ret.join(join.is_a?(::String) ? join : ' ')
|
|
110
94
|
end
|
|
111
95
|
|
|
112
|
-
def
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
key = File.basename(key, '.*') if Rake::Win32.windows?
|
|
116
|
-
shell_quote((env && ENV["PATH_#{key}"]) || PATH[key] || PATH[key.to_sym] || name,
|
|
117
|
-
option: false, force: false, double: true)
|
|
96
|
+
def line_width(lines)
|
|
97
|
+
ret = [lines.max_by(&:size).size, 80].max
|
|
98
|
+
[ret, Rake.application.terminal_width].min
|
|
118
99
|
end
|
|
119
100
|
|
|
120
101
|
def fill_option(val, **kwargs)
|
|
121
|
-
return val unless val.is_a?(::String)
|
|
122
102
|
return "-#{val}" if val.match?(/\A(?:[a-z]\d*|\d)\z/i)
|
|
123
103
|
|
|
124
104
|
shell_escape(val.start_with?('-') ? val : "--#{val}", **kwargs)
|
|
125
105
|
end
|
|
126
106
|
|
|
127
|
-
def quote_option(flag, val,
|
|
128
|
-
shell_option(flag, val, escape: false,
|
|
107
|
+
def quote_option(flag, val, **kwargs)
|
|
108
|
+
shell_option(flag, val, escape: false, **kwargs)
|
|
129
109
|
end
|
|
130
110
|
|
|
131
|
-
def basic_option(flag, val,
|
|
132
|
-
shell_option(flag, val, escape: false, force: false,
|
|
111
|
+
def basic_option(flag, val, **kwargs)
|
|
112
|
+
shell_option(flag, val, escape: false, force: false, **kwargs)
|
|
133
113
|
end
|
|
134
114
|
end
|
|
135
115
|
end
|
|
@@ -1,55 +1,49 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'pathname'
|
|
4
|
-
require '
|
|
4
|
+
require 'fileutils'
|
|
5
5
|
|
|
6
6
|
module Squared
|
|
7
7
|
module Common
|
|
8
8
|
module System
|
|
9
9
|
module_function
|
|
10
10
|
|
|
11
|
-
def shell(*args,
|
|
12
|
-
if
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
else
|
|
19
|
-
ret = Kernel.send(name, *args)
|
|
20
|
-
end
|
|
21
|
-
elsif RUBY_VERSION < '2.6'
|
|
22
|
-
e = kwargs.delete(:exception)
|
|
23
|
-
ret = Kernel.send(name, *args, **kwargs)
|
|
11
|
+
def shell(*args, **kwargs)
|
|
12
|
+
if RUBY_VERSION < '2.6'
|
|
13
|
+
exception = kwargs.delete(:exception)
|
|
14
|
+
ret = Kernel.system(*args, **kwargs)
|
|
15
|
+
return ret if ret || !exception
|
|
16
|
+
|
|
17
|
+
raise $?.to_s
|
|
24
18
|
else
|
|
25
|
-
|
|
19
|
+
Kernel.system(*args, **kwargs)
|
|
26
20
|
end
|
|
27
|
-
return ret unless e && !ret && name == :system
|
|
28
|
-
|
|
29
|
-
raise $?.to_s
|
|
30
21
|
end
|
|
31
22
|
|
|
32
|
-
def copy_dir(src, dest, glob = ['**/*'], create: false, link: nil, force: false, pass: nil,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
23
|
+
def copy_dir(src, dest, glob = ['**/*'], create: false, link: nil, force: false, pass: nil, hidden: false,
|
|
24
|
+
verbose: true)
|
|
25
|
+
base = Pathname.new(src)
|
|
26
|
+
target = Pathname.new(dest)
|
|
27
|
+
raise "#{target.cleanpath} (not found)" if !create && !target.parent.exist?
|
|
36
28
|
|
|
37
29
|
subdir = {}
|
|
38
|
-
|
|
30
|
+
target.mkpath if create
|
|
31
|
+
flags = hidden ? [File::FNM_DOTMATCH] : []
|
|
39
32
|
if pass
|
|
40
33
|
exclude = []
|
|
41
|
-
|
|
34
|
+
pass = [pass] unless pass.is_a?(::Array)
|
|
35
|
+
pass.each { |val| exclude.concat(Dir.glob(val, *flags, base: base)) }
|
|
42
36
|
end
|
|
43
|
-
|
|
44
|
-
Dir.glob(
|
|
45
|
-
next if exclude&.include?(
|
|
37
|
+
(glob.is_a?(::Enumerable) ? glob : [glob]).each do |val|
|
|
38
|
+
Dir.glob(val, *flags, base: base) do |file|
|
|
39
|
+
next if exclude&.include?(file) || (entry = base + file).directory?
|
|
46
40
|
|
|
47
|
-
dir =
|
|
41
|
+
dir = target.join(file).dirname
|
|
48
42
|
if (data = subdir[dir.to_s])
|
|
49
|
-
data <<
|
|
43
|
+
data << entry
|
|
50
44
|
else
|
|
51
45
|
dir.mkpath
|
|
52
|
-
subdir[dir.to_s] = [
|
|
46
|
+
subdir[dir.to_s] = [entry]
|
|
53
47
|
end
|
|
54
48
|
end
|
|
55
49
|
end
|
|
@@ -57,13 +51,14 @@ module Squared
|
|
|
57
51
|
soft = 0
|
|
58
52
|
subdir.each do |dir, files|
|
|
59
53
|
if link
|
|
60
|
-
files.dup.
|
|
54
|
+
files.dup.yield_self do |items|
|
|
61
55
|
files.clear
|
|
62
56
|
items.each do |file|
|
|
63
57
|
if file.exist?
|
|
64
|
-
if
|
|
58
|
+
if file.symlink?
|
|
59
|
+
next unless force
|
|
60
|
+
else
|
|
65
61
|
files << file
|
|
66
|
-
elsif !force
|
|
67
62
|
next
|
|
68
63
|
end
|
|
69
64
|
end
|
|
@@ -81,15 +76,17 @@ module Squared
|
|
|
81
76
|
out = FileUtils.cp(files, dir, verbose: false)
|
|
82
77
|
count += out.size
|
|
83
78
|
end
|
|
84
|
-
puts [
|
|
79
|
+
puts [target.realpath, subdir.size, soft > 0 ? "#{count}+#{soft}" : count].join(' => ') if verbose
|
|
85
80
|
end
|
|
86
81
|
|
|
87
82
|
def copy_guard(src, dest, link: nil, force: false, verbose: true)
|
|
88
83
|
unless force
|
|
89
|
-
|
|
90
|
-
|
|
84
|
+
target = Pathname.new(dest)
|
|
85
|
+
if target.directory?
|
|
86
|
+
src = [src] unless src.is_a?(::Enumerable)
|
|
87
|
+
src = src.reject { |val| target.join(File.basename(val)).exist? }
|
|
91
88
|
return if src.empty?
|
|
92
|
-
elsif
|
|
89
|
+
elsif target.exist?
|
|
93
90
|
return
|
|
94
91
|
end
|
|
95
92
|
end
|