squared 0.4.30 → 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 +62 -429
- data/README.md +1279 -650
- data/README.ruby.md +722 -0
- data/lib/squared/common/base.rb +8 -9
- data/lib/squared/common/format.rb +24 -31
- data/lib/squared/common/prompt.rb +46 -47
- data/lib/squared/common/shell.rb +50 -64
- 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 +26 -25
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/application.rb +74 -95
- data/lib/squared/workspace/project/base.rb +408 -536
- data/lib/squared/workspace/project/docker.rb +177 -206
- data/lib/squared/workspace/project/git.rb +361 -503
- data/lib/squared/workspace/project/node.rb +188 -296
- data/lib/squared/workspace/project/python.rb +88 -306
- data/lib/squared/workspace/project/ruby.rb +232 -306
- data/lib/squared/workspace/project/support/class.rb +93 -300
- data/lib/squared/workspace/project.rb +0 -10
- data/lib/squared/workspace/repo.rb +55 -96
- data/lib/squared/workspace/series.rb +34 -32
- data/lib/squared/workspace/support/data.rb +3 -2
- data/lib/squared/workspace/support.rb +0 -1
- data/lib/squared/workspace.rb +1 -1
- data/squared.gemspec +5 -5
- metadata +7 -8
- data/lib/squared/common/class.rb +0 -175
- 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,7 +61,7 @@ module Squared
|
|
|
67
61
|
end
|
|
68
62
|
wrap = ->(s, n) { "\x1B[#{n.join(';')}m#{s}\x1B[0m" }
|
|
69
63
|
code = []
|
|
70
|
-
args.concat(
|
|
64
|
+
args.concat(as_a(styles)).flatten.each_with_index do |type, i|
|
|
71
65
|
next unless type
|
|
72
66
|
|
|
73
67
|
if index == -1
|
|
@@ -108,7 +102,7 @@ module Squared
|
|
|
108
102
|
ret = wrap.call(ret, code) unless code.empty?
|
|
109
103
|
return ret unless data
|
|
110
104
|
|
|
111
|
-
out =
|
|
105
|
+
out = ''.dup
|
|
112
106
|
data.to_a.each_with_index do |group, i|
|
|
113
107
|
next if i == 0
|
|
114
108
|
|
|
@@ -141,11 +135,11 @@ module Squared
|
|
|
141
135
|
def apply_style(data, key, args, empty: true)
|
|
142
136
|
return if data.is_a?(::Symbol) && (data = __get__(:theme)[data]).nil?
|
|
143
137
|
|
|
144
|
-
set = ->(k, v) { data[k
|
|
138
|
+
set = ->(k, v) { data[k] = check_style(v, empty: empty) }
|
|
145
139
|
if key.is_a?(::Hash)
|
|
146
140
|
key.each { |k, v| set.call(k, v || args) }
|
|
147
141
|
else
|
|
148
|
-
set.call(key, args)
|
|
142
|
+
set.call(key.to_sym, args)
|
|
149
143
|
end
|
|
150
144
|
end
|
|
151
145
|
|
|
@@ -157,8 +151,7 @@ module Squared
|
|
|
157
151
|
when Logger::WARN then :warn
|
|
158
152
|
when Logger::ERROR then :error
|
|
159
153
|
when Logger::FATAL then :fatal
|
|
160
|
-
else :unknown
|
|
161
|
-
end
|
|
154
|
+
else :unknown end
|
|
162
155
|
else
|
|
163
156
|
level.to_s.downcase.to_sym
|
|
164
157
|
end
|
|
@@ -178,9 +171,8 @@ module Squared
|
|
|
178
171
|
args = args.map(&:to_s)
|
|
179
172
|
if level.is_a?(::Numeric)
|
|
180
173
|
if append && respond_to?(:log)
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
end
|
|
174
|
+
ref = log rescue nil
|
|
175
|
+
ref.add(level, message(subject, *args, hint: hint, space: ', ')) if ref.is_a?(Logger)
|
|
184
176
|
end
|
|
185
177
|
return false if !pass && level < ARG[:LEVEL]
|
|
186
178
|
end
|
|
@@ -190,16 +182,16 @@ module Squared
|
|
|
190
182
|
emphasize(args, title: title + (subject ? " #{subject}" : ''), sub: sub, pipe: -1)
|
|
191
183
|
else
|
|
192
184
|
msg = [log_title(level, color: color)]
|
|
193
|
-
msg << (color ? sub_style(subject
|
|
185
|
+
msg << (color ? sub_style(subject, styles: (@theme && @theme[:subject]) || :bold) : subject) if subject
|
|
194
186
|
msg << args.shift if msg.size == 1
|
|
195
187
|
message(msg.join(' '), *args, hint: hint)
|
|
196
188
|
end
|
|
197
189
|
end
|
|
198
190
|
|
|
199
|
-
def
|
|
191
|
+
def puts_oe(*args, pipe: 1)
|
|
200
192
|
return if args.first == false && args.size == 1
|
|
201
193
|
|
|
202
|
-
if pipe.is_a?(
|
|
194
|
+
if pipe.is_a?(Pathname)
|
|
203
195
|
begin
|
|
204
196
|
File.open(pipe, 'a') do |f|
|
|
205
197
|
br = File::SEPARATOR == '\\' ? "\r\n" : "\n"
|
|
@@ -213,27 +205,28 @@ module Squared
|
|
|
213
205
|
(pipe == 2 ? $stderr : $stdout).puts(*args)
|
|
214
206
|
end
|
|
215
207
|
|
|
216
|
-
alias puts_oe log_console
|
|
217
|
-
|
|
218
208
|
module_function
|
|
219
209
|
|
|
220
210
|
def message(*args, hint: nil, empty: false, space: ARG[:SPACE])
|
|
221
|
-
(empty ? args.reject { |val| val.nil? ||
|
|
222
|
-
.join(space) + (hint ? " (#{hint})" : '')
|
|
211
|
+
(empty ? args.reject { |val| val.nil? || val.empty? } : args).join(space) + (hint ? " (#{hint})" : '')
|
|
223
212
|
end
|
|
224
213
|
|
|
225
214
|
def emphasize(val, title: nil, footer: nil, right: false, cols: nil, sub: nil, pipe: nil,
|
|
226
|
-
border: @theme
|
|
215
|
+
border: @theme && @theme[:border])
|
|
227
216
|
n = 0
|
|
228
|
-
max = ->(
|
|
229
|
-
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
|
|
230
223
|
title &&= set.call(title)
|
|
231
224
|
footer &&= set.call(footer)
|
|
232
225
|
if val.is_a?(::Array)
|
|
233
226
|
lines = val.map(&:to_s)
|
|
234
227
|
else
|
|
235
228
|
lines = val.to_s.lines(chomp: true)
|
|
236
|
-
lines[0] = "#{val.class}: #{lines.first}" if (err = val.is_a?(
|
|
229
|
+
lines[0] = "#{val.class}: #{lines.first}" if (err = val.is_a?(StandardError))
|
|
237
230
|
end
|
|
238
231
|
n = cols || max.call(lines)
|
|
239
232
|
if $stdout.tty?
|
|
@@ -253,8 +246,8 @@ module Squared
|
|
|
253
246
|
sub.each { |h| s = sub_style(s, **h) }
|
|
254
247
|
s = "#{b0} #{s} #{b0}"
|
|
255
248
|
if border
|
|
256
|
-
s = sub_style(s, pat: /\A(#{Regexp.escape(b0)})(.+)\z/
|
|
257
|
-
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)
|
|
258
251
|
end
|
|
259
252
|
s
|
|
260
253
|
end
|
|
@@ -288,7 +281,7 @@ module Squared
|
|
|
288
281
|
else
|
|
289
282
|
pipe = $stdout unless pipe.respond_to?(:puts)
|
|
290
283
|
end
|
|
291
|
-
pipe.puts
|
|
284
|
+
pipe.puts out
|
|
292
285
|
else
|
|
293
286
|
err ? warn(out) : puts(out)
|
|
294
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,19 +93,19 @@ module Squared
|
|
|
94
93
|
elsif block_given?
|
|
95
94
|
Readline.readmultiline(msg, history, &blk)
|
|
96
95
|
else
|
|
97
|
-
Readline.readmultiline(msg, history) { |line| multiline.any? { |val| line.split.last.end_with?(val
|
|
96
|
+
Readline.readmultiline(msg, history) { |line| multiline.any? { |val| line.split.last.end_with?(val) } }
|
|
98
97
|
end
|
|
99
98
|
end
|
|
100
99
|
case force
|
|
101
100
|
when ::TrueClass, ::FalseClass
|
|
102
101
|
msg = "#{msg} %s " % if multiline
|
|
103
|
-
multiline.is_a?(::Enumerable) ? "{#{multiline.
|
|
102
|
+
multiline.is_a?(::Enumerable) ? "{#{multiline.join('|')}}" : multiline
|
|
104
103
|
else
|
|
105
104
|
"(#{force ? 'required' : 'optional'}):"
|
|
106
105
|
end
|
|
107
106
|
ret = (prompt.call || '').strip
|
|
108
|
-
multiline.each { |val| break if ret.delete_suffix!(val
|
|
109
|
-
|
|
107
|
+
multiline.each { |val| break if ret.delete_suffix!(val) } if multiline.is_a?(::Enumerable)
|
|
108
|
+
raise_error 'user cancelled' if force && ret.empty?
|
|
110
109
|
ret
|
|
111
110
|
else
|
|
112
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,92 +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
|
-
end}"
|
|
98
|
-
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}"
|
|
99
86
|
end
|
|
100
87
|
|
|
101
|
-
def shell_split(val,
|
|
102
|
-
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) }
|
|
103
91
|
return ret unless join
|
|
104
92
|
|
|
105
93
|
ret.join(join.is_a?(::String) ? join : ' ')
|
|
106
94
|
end
|
|
107
95
|
|
|
108
|
-
def
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
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
|
|
112
99
|
end
|
|
113
100
|
|
|
114
101
|
def fill_option(val, **kwargs)
|
|
115
|
-
return val unless val.is_a?(::String)
|
|
116
102
|
return "-#{val}" if val.match?(/\A(?:[a-z]\d*|\d)\z/i)
|
|
117
103
|
|
|
118
104
|
shell_escape(val.start_with?('-') ? val : "--#{val}", **kwargs)
|
|
119
105
|
end
|
|
120
106
|
|
|
121
|
-
def quote_option(flag, val,
|
|
122
|
-
shell_option(flag, val, escape: false,
|
|
107
|
+
def quote_option(flag, val, **kwargs)
|
|
108
|
+
shell_option(flag, val, escape: false, **kwargs)
|
|
123
109
|
end
|
|
124
110
|
|
|
125
|
-
def basic_option(flag, val,
|
|
126
|
-
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)
|
|
127
113
|
end
|
|
128
114
|
end
|
|
129
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
|