squared 0.4.2 → 0.4.4
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 +65 -0
- data/README.ruby.md +131 -61
- data/lib/squared/common/base.rb +2 -1
- data/lib/squared/common/format.rb +2 -6
- data/lib/squared/common/shell.rb +2 -1
- data/lib/squared/common/utils.rb +8 -5
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/application.rb +10 -1
- data/lib/squared/workspace/project/base.rb +114 -46
- data/lib/squared/workspace/project/docker.rb +123 -53
- data/lib/squared/workspace/project/git.rb +72 -66
- data/lib/squared/workspace/project/node.rb +25 -27
- data/lib/squared/workspace/project/python.rb +213 -79
- data/lib/squared/workspace/project/ruby.rb +96 -40
- data/lib/squared/workspace/repo.rb +1 -1
- metadata +2 -2
@@ -11,10 +11,11 @@ module Squared
|
|
11
11
|
include Common::Format
|
12
12
|
include System
|
13
13
|
include Shell
|
14
|
+
include Prompt
|
14
15
|
include Utils
|
15
16
|
include Rake::DSL
|
16
17
|
|
17
|
-
VAR_SET = %i[parent global envname dependfile theme run script env pass].freeze
|
18
|
+
VAR_SET = %i[parent global envname dependfile dependindex theme run script env pass].freeze
|
18
19
|
BLK_SET = %i[run depend doc lint test copy clean].freeze
|
19
20
|
SEM_VER = /\b(\d+)(?:(\.)(\d+))?(?:(\.)(\d+)(\S+)?)?\b/.freeze
|
20
21
|
URI_SCHEME = %r{^([a-z][a-z\d+-.]*)://[^@:\[\]\\^<>|\s]}i.freeze
|
@@ -43,6 +44,10 @@ module Squared
|
|
43
44
|
@ref ||= to_s.downcase.to_sym
|
44
45
|
end
|
45
46
|
|
47
|
+
def subtasks(val)
|
48
|
+
@@tasks[ref] = val.freeze
|
49
|
+
end
|
50
|
+
|
46
51
|
def config?(*)
|
47
52
|
false
|
48
53
|
end
|
@@ -52,13 +57,15 @@ module Squared
|
|
52
57
|
end
|
53
58
|
end
|
54
59
|
|
55
|
-
|
56
|
-
'graph' => %i[run print].freeze,
|
57
|
-
'unpack' => %i[zip tar tgz tar.gz txz tar.xz].freeze
|
58
|
-
}.freeze
|
60
|
+
@@tasks = {}
|
59
61
|
@@task_desc = Rake::TaskManager.record_task_metadata
|
60
62
|
@@print_order = 0
|
61
63
|
|
64
|
+
subtasks({
|
65
|
+
'graph' => %i[run print].freeze,
|
66
|
+
'unpack' => %i[zip tar ext].freeze
|
67
|
+
})
|
68
|
+
|
62
69
|
attr_reader :name, :project, :workspace, :path, :theme, :exception, :pipe, :verbose,
|
63
70
|
:group, :parent, :dependfile
|
64
71
|
|
@@ -218,9 +225,8 @@ module Squared
|
|
218
225
|
def initialize_env(dev: nil, prod: nil, **)
|
219
226
|
@dev = env_match('BUILD', dev, suffix: 'DEV', strict: true)
|
220
227
|
@prod = env_match('BUILD', prod, suffix: 'PROD', strict: true)
|
221
|
-
|
222
|
-
|
223
|
-
@output[2] = data if data
|
228
|
+
if @output[2] != false && (val = env('BUILD', suffix: 'ENV'))
|
229
|
+
@output[2] = parse_json(val, hint: "BUILD_#{@envname}_ENV") || @output[2]
|
224
230
|
end
|
225
231
|
unless @output[0] == false || @output[0].is_a?(Array)
|
226
232
|
if (val = env('BUILD', suffix: 'OPTS'))
|
@@ -286,8 +292,11 @@ module Squared
|
|
286
292
|
end
|
287
293
|
end
|
288
294
|
when 'unpack'
|
289
|
-
format_desc
|
290
|
-
|
295
|
+
format_desc(action, flag, 'tag/url,dir,digest?,f/force?', before: flag == :ext ? 'ext' : nil)
|
296
|
+
params = %i[tag dir digest force]
|
297
|
+
params.unshift(:ext) if flag == :ext
|
298
|
+
task flag, params do |_, args|
|
299
|
+
ext = param_guard(action, flag, args: args, key: :ext).downcase if flag == :ext
|
291
300
|
tag = param_guard(action, flag, args: args, key: :tag)
|
292
301
|
dir = param_guard(action, flag, args: args, key: :dir)
|
293
302
|
unless tag.match?(URI_SCHEME)
|
@@ -302,7 +311,7 @@ module Squared
|
|
302
311
|
else
|
303
312
|
force = args.fetch(:force, false)
|
304
313
|
end
|
305
|
-
unpack(basepath(dir), uri: tag, digest: digest, ext: flag.to_s, force: force)
|
314
|
+
unpack(basepath(dir), uri: tag, digest: digest, ext: ext || flag.to_s, force: force)
|
306
315
|
end
|
307
316
|
end
|
308
317
|
end
|
@@ -386,7 +395,7 @@ module Squared
|
|
386
395
|
|
387
396
|
run_b(@run, sync: sync, from: from) if series?(@run)
|
388
397
|
args = @output
|
389
|
-
banner = verbose == 1 if task_invoked?('build', 'build:sync')
|
398
|
+
banner = verbose == 1 if task_invoked?('build', 'build:sync', 'default')
|
390
399
|
end
|
391
400
|
if args.all? { |val| val.is_a?(Array) }
|
392
401
|
cmd = []
|
@@ -570,8 +579,8 @@ module Squared
|
|
570
579
|
raise_error("invalid checksum: #{digest}", hint: name)
|
571
580
|
end
|
572
581
|
end
|
573
|
-
if (val = env('HEADERS')) && (
|
574
|
-
headers =
|
582
|
+
if (val = env('HEADERS')) && (val = parse_json(val, hint: "HEADERS_#{@envname}"))
|
583
|
+
headers = val
|
575
584
|
end
|
576
585
|
require 'open-uri'
|
577
586
|
data = nil
|
@@ -602,7 +611,7 @@ module Squared
|
|
602
611
|
end
|
603
612
|
end
|
604
613
|
ext ||= URI.parse(uri).path[/^.+?\.((?:tar\.)?\w+)$/i, 1]
|
605
|
-
if (n = env("#{ext == 'zip'
|
614
|
+
if (n = env("#{ext == 'zip' || ext == '7z' ? ext.upcase : 'TAR'}_DEPTH", ignore: false))
|
606
615
|
depth = n.to_i
|
607
616
|
end
|
608
617
|
begin
|
@@ -611,24 +620,25 @@ module Squared
|
|
611
620
|
file.write(data)
|
612
621
|
file.close
|
613
622
|
if create
|
614
|
-
warn log_message(Logger::WARN,
|
615
|
-
target.rmtree
|
623
|
+
warn log_message(Logger::WARN, 'force remove', subject: name, hint: target, pass: true)
|
624
|
+
target.rmtree
|
616
625
|
target.mkpath
|
617
626
|
end
|
618
627
|
case ext
|
619
628
|
when 'zip', 'aar'
|
620
629
|
session 'unzip', shell_quote(file.path), quote_option('d', target)
|
621
|
-
when 'tar', 'tgz', 'tar.gz', 'tar.xz'
|
630
|
+
when 'tar', 'tgz', 'tar.gz', 'tar.xz', 'gz', 'xz'
|
622
631
|
flags = +(verbose ? 'v' : '')
|
623
|
-
|
624
|
-
when 'tgz', 'tar.gz'
|
632
|
+
if ext.end_with?('gz')
|
625
633
|
flags += 'z'
|
626
|
-
|
634
|
+
elsif ext.end_with?('xz')
|
627
635
|
flags += 'J'
|
628
636
|
end
|
629
637
|
session 'tar', "-x#{flags}", basic_option('strip-components', depth), quote_option('f', file.path),
|
630
638
|
quote_option('C', target)
|
631
639
|
depth = 0
|
640
|
+
when '7z'
|
641
|
+
session '7z', 'x', shell_quote(file.path), "-o#{shell_quote(target)}"
|
632
642
|
else
|
633
643
|
raise_error("unsupported format: #{ext}", hint: uri)
|
634
644
|
end
|
@@ -790,9 +800,7 @@ module Squared
|
|
790
800
|
end
|
791
801
|
|
792
802
|
def exclude?(*refs)
|
793
|
-
|
794
|
-
|
795
|
-
refs.flatten.any? { |ref| @exclude.include?(ref) }
|
803
|
+
!@exclude.empty? && has_value?(@exclude, refs.flatten)
|
796
804
|
end
|
797
805
|
|
798
806
|
def task_include?(key, ref = nil)
|
@@ -868,19 +876,33 @@ module Squared
|
|
868
876
|
on :first, from
|
869
877
|
begin
|
870
878
|
if cmd.match?(/\A[^:]+:[^:]/) && workspace.task_defined?(cmd)
|
871
|
-
log&.warn "ENV
|
879
|
+
log&.warn "ENV discarded: #{var}" if var
|
872
880
|
task_invoke(cmd, exception: exception, warning: warning?)
|
873
881
|
else
|
874
|
-
print_item format_banner(cmd, banner: banner) if sync
|
882
|
+
print_item format_banner(cmd, banner: banner) if sync
|
883
|
+
if var.is_a?(Hash)
|
884
|
+
case (pre = runenv)
|
885
|
+
when Hash
|
886
|
+
var = pre.merge(var)
|
887
|
+
when String
|
888
|
+
cmd = "#{pre} && #{cmd}"
|
889
|
+
end
|
890
|
+
elsif var != false && (var = runenv).is_a?(String)
|
891
|
+
cmd = "#{var} && #{cmd}"
|
892
|
+
var = nil
|
893
|
+
end
|
875
894
|
args = var.is_a?(Hash) ? [var, cmd] : [cmd]
|
876
|
-
shell(*args, chdir: chdir, exception: exception)
|
895
|
+
ret = shell(*args, chdir: chdir, exception: exception)
|
877
896
|
end
|
878
897
|
rescue StandardError => e
|
879
898
|
log&.error e
|
880
899
|
ret = on(:error, from, e)
|
881
900
|
raise unless ret == true
|
901
|
+
|
902
|
+
false
|
882
903
|
else
|
883
904
|
on :last, from
|
905
|
+
ret
|
884
906
|
end
|
885
907
|
end
|
886
908
|
|
@@ -1044,9 +1066,9 @@ module Squared
|
|
1044
1066
|
ret.empty? || (ignore && as_a(ignore).any? { |val| ret == val.to_s }) ? default : ret
|
1045
1067
|
end
|
1046
1068
|
|
1047
|
-
def session(*cmd, prefix: cmd.first, main: true, options: true)
|
1069
|
+
def session(*cmd, prefix: cmd.first, main: true, path: true, options: true)
|
1048
1070
|
prefix = prefix.to_s.upcase
|
1049
|
-
if (val = PATH[prefix] || PATH[prefix.to_sym])
|
1071
|
+
if path && (val = PATH[prefix] || PATH[prefix.to_sym])
|
1050
1072
|
cmd[0] = shell_quote(val, force: false)
|
1051
1073
|
end
|
1052
1074
|
ret = JoinSet.new(cmd.flatten(1))
|
@@ -1059,7 +1081,8 @@ module Squared
|
|
1059
1081
|
def session_delete(*list, target: @session)
|
1060
1082
|
ret = []
|
1061
1083
|
list.each do |val|
|
1062
|
-
|
1084
|
+
pat = /^#{Regexp.escape(shell_option(val))}(?: |=|$)/
|
1085
|
+
if (key = target.find { |opt| opt.match?(pat) })
|
1063
1086
|
target.delete(key)
|
1064
1087
|
ret << key
|
1065
1088
|
end
|
@@ -1089,7 +1112,7 @@ module Squared
|
|
1089
1112
|
nil
|
1090
1113
|
end
|
1091
1114
|
|
1092
|
-
def option_sanitize(opts, list, target: @session, no: nil, first: false, pass: ['='])
|
1115
|
+
def option_sanitize(opts, list, target: @session, no: nil, single: nil, args: false, first: false, pass: ['='])
|
1093
1116
|
ret = []
|
1094
1117
|
reg = []
|
1095
1118
|
bare = []
|
@@ -1101,6 +1124,7 @@ module Squared
|
|
1101
1124
|
qq = []
|
1102
1125
|
i = []
|
1103
1126
|
f = []
|
1127
|
+
si = []
|
1104
1128
|
list = list.map do |val|
|
1105
1129
|
x, y = val.split('|')
|
1106
1130
|
if y
|
@@ -1131,6 +1155,8 @@ module Squared
|
|
1131
1155
|
i << flag
|
1132
1156
|
when 'f'
|
1133
1157
|
f << flag
|
1158
|
+
when 'n'
|
1159
|
+
si << flag
|
1134
1160
|
else
|
1135
1161
|
reg << Regexp.escape(flag)
|
1136
1162
|
end
|
@@ -1145,12 +1171,14 @@ module Squared
|
|
1145
1171
|
opts.each do |opt|
|
1146
1172
|
next ret << opt if found
|
1147
1173
|
|
1148
|
-
if
|
1174
|
+
if single&.match?(opt)
|
1175
|
+
target << "-#{opt}"
|
1176
|
+
elsif bare.include?(opt)
|
1149
1177
|
target << (opt.size == 1 ? "-#{opt}" : "--#{opt}")
|
1150
1178
|
elsif opt.start_with?('no-') && no.include?(name = opt[3..-1])
|
1151
1179
|
target << "--no-#{name}"
|
1152
1180
|
else
|
1153
|
-
if opt =~
|
1181
|
+
if opt =~ /\A([^=]+)=(.+)\z/
|
1154
1182
|
key = $1
|
1155
1183
|
val = $2
|
1156
1184
|
match = ->(flag, pat) { flag.include?(key) && pat.match?(val) }
|
@@ -1162,7 +1190,7 @@ module Squared
|
|
1162
1190
|
target << quote_option(key, basepath(val))
|
1163
1191
|
elsif m.include?(key)
|
1164
1192
|
target << basic_option(key, val, merge: true)
|
1165
|
-
elsif b.include?(key) || match.(i, /^\d+$/) || match.(f, /^\d*(?:\.\d+)?$/)
|
1193
|
+
elsif b.include?(key) || match.(i, /^\d+$/) || match.(f, /^\d*(?:\.\d+)?$/) || match.(si, /^-?\d+$/)
|
1166
1194
|
target << basic_option(key, val)
|
1167
1195
|
else
|
1168
1196
|
ret << opt
|
@@ -1170,6 +1198,7 @@ module Squared
|
|
1170
1198
|
opt = key
|
1171
1199
|
else
|
1172
1200
|
ret << opt
|
1201
|
+
found = true if args
|
1173
1202
|
end
|
1174
1203
|
found = true if first && pass.none? { |s| opt.include?(s) }
|
1175
1204
|
end
|
@@ -1177,14 +1206,20 @@ module Squared
|
|
1177
1206
|
[ret, reg.empty? ? /\A\s+\z/ : /^(#{reg.join('|')})=(.+)$/]
|
1178
1207
|
end
|
1179
1208
|
|
1180
|
-
def option_clear(opts, target: @session, **kwargs)
|
1209
|
+
def option_clear(opts, target: @session, pass: true, append: false, **kwargs)
|
1210
|
+
return if opts.empty?
|
1211
|
+
|
1181
1212
|
kwargs[:subject] ||= target&.first
|
1182
|
-
kwargs[:hint] ||= '
|
1183
|
-
warn log_message(Logger::WARN, opts.join(', '), pass: true, **kwargs)
|
1213
|
+
kwargs[:hint] ||= 'unrecognized'
|
1214
|
+
warn log_message(Logger::WARN, opts.join(', '), pass: true, **kwargs)
|
1215
|
+
append_value(opts, delim: true) if append
|
1216
|
+
return if pass || confirm("Run? [#{sub_style(target, styles: theme[:inline])}] [y/N] ", 'N', timeout: 30)
|
1217
|
+
|
1218
|
+
raise_error 'user cancelled'
|
1184
1219
|
end
|
1185
1220
|
|
1186
1221
|
def print_item(*val)
|
1187
|
-
puts if @@print_order > 0 &&
|
1222
|
+
puts if @@print_order > 0 && stdout?
|
1188
1223
|
@@print_order += 1
|
1189
1224
|
puts val unless val.empty? || (val.size == 1 && val.first.nil?)
|
1190
1225
|
end
|
@@ -1236,7 +1271,7 @@ module Squared
|
|
1236
1271
|
end
|
1237
1272
|
|
1238
1273
|
def format_banner(cmd, banner: true)
|
1239
|
-
return unless banner &&
|
1274
|
+
return unless banner && banner?
|
1240
1275
|
|
1241
1276
|
if (data = workspace.banner_get(*@ref, group: group))
|
1242
1277
|
return if data.empty?
|
@@ -1468,18 +1503,19 @@ module Squared
|
|
1468
1503
|
ret
|
1469
1504
|
end
|
1470
1505
|
|
1471
|
-
def parse_json(val, hint: nil)
|
1506
|
+
def parse_json(val, kind: Hash, hint: nil)
|
1472
1507
|
ret = JSON.parse(val)
|
1473
|
-
raise_error(
|
1508
|
+
raise_error("invalid JSON #{kind.name}", val, hint: hint) if kind && !ret.is_a?(kind)
|
1474
1509
|
rescue StandardError => e
|
1475
1510
|
log&.warn e
|
1511
|
+
warn log_message(Logger::WARN, e, subject: name, pass: true) if warning?
|
1476
1512
|
else
|
1477
1513
|
ret
|
1478
1514
|
end
|
1479
1515
|
|
1480
1516
|
def param_guard(action, flag, args: nil, key: nil, pat: nil, values: nil)
|
1481
1517
|
if args && key
|
1482
|
-
val = args
|
1518
|
+
val = args.fetch(key, nil)
|
1483
1519
|
return val unless val.nil? || (pat && !val.match?(pat)) || (values && !values.include?(val))
|
1484
1520
|
|
1485
1521
|
@session = nil
|
@@ -1491,19 +1527,28 @@ module Squared
|
|
1491
1527
|
args
|
1492
1528
|
end
|
1493
1529
|
|
1530
|
+
def runenv
|
1531
|
+
nil
|
1532
|
+
end
|
1533
|
+
|
1494
1534
|
def relativepath(*files, all: false)
|
1495
1535
|
return [] if files.empty?
|
1496
1536
|
|
1537
|
+
pat = /^#{Regexp.escape(File.join(path, ''))}/
|
1497
1538
|
files.flatten.map { |val| Pathname.new(val) }.select { |val| projectpath?(val) }.map do |val|
|
1498
|
-
val = val.absolute? ? val.to_s.sub(
|
1539
|
+
val = val.absolute? ? val.to_s.sub(pat, '') : val.to_s
|
1499
1540
|
val = val[2..-1] if val.start_with?('./')
|
1500
1541
|
val = "#{val}*" if all && val.end_with?('/')
|
1501
1542
|
val
|
1502
1543
|
end
|
1503
1544
|
end
|
1504
1545
|
|
1505
|
-
def projectmap(files, parent: false)
|
1506
|
-
|
1546
|
+
def projectmap(files, parent: false, pass: true)
|
1547
|
+
unless parent
|
1548
|
+
project = files.select { |val| projectpath?(val) }
|
1549
|
+
raise_error 'pathspec not within worktree' unless pass || files.size == project.size
|
1550
|
+
files = project
|
1551
|
+
end
|
1507
1552
|
files.map { |val| val == '.' ? '.' : shell_quote(basepath(val.strip)) }
|
1508
1553
|
end
|
1509
1554
|
|
@@ -1716,7 +1761,8 @@ module Squared
|
|
1716
1761
|
|
1717
1762
|
def session_arg?(*list, target: @session, value: false)
|
1718
1763
|
list.any? do |val|
|
1719
|
-
|
1764
|
+
pat = /^#{Regexp.escape(shell_option(val))}#{value ? '[ =].' : '(?:[ =]|$)'}/
|
1765
|
+
target.any? { |opt| opt.match?(pat) }
|
1720
1766
|
end
|
1721
1767
|
end
|
1722
1768
|
|
@@ -1741,14 +1787,36 @@ module Squared
|
|
1741
1787
|
end
|
1742
1788
|
end
|
1743
1789
|
|
1790
|
+
def banner?
|
1791
|
+
ARG[:BANNER] && !env('BANNER', equals: '0')
|
1792
|
+
end
|
1793
|
+
|
1744
1794
|
def stdin?
|
1745
1795
|
pipe == 0
|
1746
1796
|
end
|
1747
1797
|
|
1798
|
+
def stdout?
|
1799
|
+
!!verbose && !stdin?
|
1800
|
+
end
|
1801
|
+
|
1748
1802
|
def warning?
|
1749
1803
|
workspace.warning
|
1750
1804
|
end
|
1751
1805
|
|
1806
|
+
def has_value?(data, val)
|
1807
|
+
return data.value?(val) if data.is_a?(::Hash)
|
1808
|
+
return data.is_a?(::Enumerable) && data.to_a.include?(val) if !val.is_a?(::Enumerable) || val.is_a?(::Hash)
|
1809
|
+
|
1810
|
+
val.to_a.any? do |obj|
|
1811
|
+
case data
|
1812
|
+
when ::Hash
|
1813
|
+
data.value?(obj)
|
1814
|
+
when ::Enumerable
|
1815
|
+
data.to_a.include?(obj)
|
1816
|
+
end
|
1817
|
+
end
|
1818
|
+
end
|
1819
|
+
|
1752
1820
|
def variables
|
1753
1821
|
Base.tasks + VAR_SET
|
1754
1822
|
end
|