squared 0.4.3 → 0.4.5

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.
@@ -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
- (@@tasks = {})[ref] = {
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
- unless @output[2] == false || !(val = env('BUILD', suffix: 'ENV'))
222
- data = parse_json(val, hint: "BUILD_#{@envname}_ENV")
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 action, flag, 'tag/url,dir,digest?,f/force?'
290
- task flag, [:tag, :dir, :digest, :force] do |_, args|
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')) && (out = parse_json(val, hint: "HEADERS_#{@envname}"))
574
- headers = out
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' ? 'ZIP' : 'TAR'}_DEPTH", ignore: false))
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, name, 'force remove', hint: target, pass: true)
615
- target.rmtree(verbose: true)
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
- case ext
624
- when 'tgz', 'tar.gz'
632
+ if ext.end_with?('gz')
625
633
  flags += 'z'
626
- when 'txz', 'tar.xz'
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
- return false if @exclude.empty?
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,32 @@ module Squared
868
876
  on :first, from
869
877
  begin
870
878
  if cmd.match?(/\A[^:]+:[^:]/) && workspace.task_defined?(cmd)
871
- log&.warn "ENV was discarded: #{var}" if var
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 && !env('BANNER', equals: '0')
882
+ print_item format_banner(cmd, banner: banner) if sync
883
+ if var != false && (pre = runenv)
884
+ case pre
885
+ when Hash
886
+ var = var.is_a?(Hash) ? pre.merge(var) : pre
887
+ when Enumerable
888
+ cmd = command(*pre.to_a, cmd)
889
+ else
890
+ cmd = command(pre, cmd)
891
+ end
892
+ end
875
893
  args = var.is_a?(Hash) ? [var, cmd] : [cmd]
876
- shell(*args, chdir: chdir, exception: exception)
894
+ ret = shell(*args, chdir: chdir, exception: exception)
877
895
  end
878
896
  rescue StandardError => e
879
897
  log&.error e
880
898
  ret = on(:error, from, e)
881
899
  raise unless ret == true
900
+
901
+ false
882
902
  else
883
903
  on :last, from
904
+ ret
884
905
  end
885
906
  end
886
907
 
@@ -1044,9 +1065,9 @@ module Squared
1044
1065
  ret.empty? || (ignore && as_a(ignore).any? { |val| ret == val.to_s }) ? default : ret
1045
1066
  end
1046
1067
 
1047
- def session(*cmd, prefix: cmd.first, main: true, options: true)
1068
+ def session(*cmd, prefix: cmd.first, main: true, path: true, options: true)
1048
1069
  prefix = prefix.to_s.upcase
1049
- if (val = PATH[prefix] || PATH[prefix.to_sym])
1070
+ if path && (val = PATH[prefix] || PATH[prefix.to_sym])
1050
1071
  cmd[0] = shell_quote(val, force: false)
1051
1072
  end
1052
1073
  ret = JoinSet.new(cmd.flatten(1))
@@ -1059,7 +1080,8 @@ module Squared
1059
1080
  def session_delete(*list, target: @session)
1060
1081
  ret = []
1061
1082
  list.each do |val|
1062
- if (key = target.find { |opt| opt.match?(/^#{Regexp.escape(shell_option(val))}(?: |=|$)/o) })
1083
+ pat = /^#{Regexp.escape(shell_option(val))}(?: |=|$)/
1084
+ if (key = target.find { |opt| opt.match?(pat) })
1063
1085
  target.delete(key)
1064
1086
  ret << key
1065
1087
  end
@@ -1089,7 +1111,7 @@ module Squared
1089
1111
  nil
1090
1112
  end
1091
1113
 
1092
- def option_sanitize(opts, list, target: @session, no: nil, first: false, pass: ['='])
1114
+ def option_sanitize(opts, list, target: @session, no: nil, single: nil, args: false, first: false, pass: ['='])
1093
1115
  ret = []
1094
1116
  reg = []
1095
1117
  bare = []
@@ -1101,6 +1123,7 @@ module Squared
1101
1123
  qq = []
1102
1124
  i = []
1103
1125
  f = []
1126
+ si = []
1104
1127
  list = list.map do |val|
1105
1128
  x, y = val.split('|')
1106
1129
  if y
@@ -1131,6 +1154,8 @@ module Squared
1131
1154
  i << flag
1132
1155
  when 'f'
1133
1156
  f << flag
1157
+ when 'n'
1158
+ si << flag
1134
1159
  else
1135
1160
  reg << Regexp.escape(flag)
1136
1161
  end
@@ -1145,12 +1170,14 @@ module Squared
1145
1170
  opts.each do |opt|
1146
1171
  next ret << opt if found
1147
1172
 
1148
- if bare.include?(opt)
1173
+ if single&.match?(opt)
1174
+ target << "-#{opt}"
1175
+ elsif bare.include?(opt)
1149
1176
  target << (opt.size == 1 ? "-#{opt}" : "--#{opt}")
1150
1177
  elsif opt.start_with?('no-') && no.include?(name = opt[3..-1])
1151
1178
  target << "--no-#{name}"
1152
1179
  else
1153
- if opt =~ /^([^=]+)=(.+)$/
1180
+ if opt =~ /\A([^=]+)=(.+)\z/
1154
1181
  key = $1
1155
1182
  val = $2
1156
1183
  match = ->(flag, pat) { flag.include?(key) && pat.match?(val) }
@@ -1162,7 +1189,7 @@ module Squared
1162
1189
  target << quote_option(key, basepath(val))
1163
1190
  elsif m.include?(key)
1164
1191
  target << basic_option(key, val, merge: true)
1165
- elsif b.include?(key) || match.(i, /^\d+$/) || match.(f, /^\d*(?:\.\d+)?$/)
1192
+ elsif b.include?(key) || match.(i, /^\d+$/) || match.(f, /^\d*(?:\.\d+)?$/) || match.(si, /^-?\d+$/)
1166
1193
  target << basic_option(key, val)
1167
1194
  else
1168
1195
  ret << opt
@@ -1170,6 +1197,7 @@ module Squared
1170
1197
  opt = key
1171
1198
  else
1172
1199
  ret << opt
1200
+ found = true if args
1173
1201
  end
1174
1202
  found = true if first && pass.none? { |s| opt.include?(s) }
1175
1203
  end
@@ -1177,14 +1205,20 @@ module Squared
1177
1205
  [ret, reg.empty? ? /\A\s+\z/ : /^(#{reg.join('|')})=(.+)$/]
1178
1206
  end
1179
1207
 
1180
- def option_clear(opts, target: @session, **kwargs)
1208
+ def option_clear(opts, target: @session, pass: true, append: false, **kwargs)
1209
+ return if opts.empty?
1210
+
1181
1211
  kwargs[:subject] ||= target&.first
1182
- kwargs[:hint] ||= 'not used'
1183
- warn log_message(Logger::WARN, opts.join(', '), pass: true, **kwargs) unless opts.empty?
1212
+ kwargs[:hint] ||= 'unrecognized'
1213
+ warn log_message(Logger::WARN, opts.join(', '), pass: true, **kwargs)
1214
+ append_value(opts, delim: true) if append
1215
+ return if pass || confirm("Run? [#{sub_style(target, styles: theme[:inline])}] [y/N] ", 'N', timeout: 30)
1216
+
1217
+ raise_error 'user cancelled'
1184
1218
  end
1185
1219
 
1186
1220
  def print_item(*val)
1187
- puts if @@print_order > 0 && verbose && !stdin?
1221
+ puts if @@print_order > 0 && stdout?
1188
1222
  @@print_order += 1
1189
1223
  puts val unless val.empty? || (val.size == 1 && val.first.nil?)
1190
1224
  end
@@ -1236,7 +1270,7 @@ module Squared
1236
1270
  end
1237
1271
 
1238
1272
  def format_banner(cmd, banner: true)
1239
- return unless banner && ARG[:BANNER]
1273
+ return unless banner && banner?
1240
1274
 
1241
1275
  if (data = workspace.banner_get(*@ref, group: group))
1242
1276
  return if data.empty?
@@ -1468,18 +1502,19 @@ module Squared
1468
1502
  ret
1469
1503
  end
1470
1504
 
1471
- def parse_json(val, hint: nil)
1505
+ def parse_json(val, kind: Hash, hint: nil)
1472
1506
  ret = JSON.parse(val)
1473
- raise_error('invalid JSON object', val, hint: hint) unless ret.is_a?(Hash)
1507
+ raise_error("invalid JSON #{kind.name}", val, hint: hint) if kind && !ret.is_a?(kind)
1474
1508
  rescue StandardError => e
1475
1509
  log&.warn e
1510
+ warn log_message(Logger::WARN, e, subject: name, pass: true) if warning?
1476
1511
  else
1477
1512
  ret
1478
1513
  end
1479
1514
 
1480
1515
  def param_guard(action, flag, args: nil, key: nil, pat: nil, values: nil)
1481
1516
  if args && key
1482
- val = args[key]
1517
+ val = args.fetch(key, nil)
1483
1518
  return val unless val.nil? || (pat && !val.match?(pat)) || (values && !values.include?(val))
1484
1519
 
1485
1520
  @session = nil
@@ -1491,19 +1526,36 @@ module Squared
1491
1526
  args
1492
1527
  end
1493
1528
 
1529
+ def runenv
1530
+ nil
1531
+ end
1532
+
1533
+ def command(*args)
1534
+ if workspace.powershell?
1535
+ "powershell.exe -Command \"& {#{args.join(' ; ')}}\""
1536
+ else
1537
+ args.join(' && ')
1538
+ end
1539
+ end
1540
+
1494
1541
  def relativepath(*files, all: false)
1495
1542
  return [] if files.empty?
1496
1543
 
1544
+ pat = /^#{Regexp.escape(File.join(path, ''))}/
1497
1545
  files.flatten.map { |val| Pathname.new(val) }.select { |val| projectpath?(val) }.map do |val|
1498
- val = val.absolute? ? val.to_s.sub(/^#{Regexp.escape(File.join(path, ''))}/o, '') : val.to_s
1546
+ val = val.absolute? ? val.to_s.sub(pat, '') : val.to_s
1499
1547
  val = val[2..-1] if val.start_with?('./')
1500
1548
  val = "#{val}*" if all && val.end_with?('/')
1501
1549
  val
1502
1550
  end
1503
1551
  end
1504
1552
 
1505
- def projectmap(files, parent: false)
1506
- files = files.select { |val| projectpath?(val) } unless parent
1553
+ def projectmap(files, parent: false, pass: true)
1554
+ unless parent
1555
+ project = files.select { |val| projectpath?(val) }
1556
+ raise_error 'pathspec not within worktree' unless pass || files.size == project.size
1557
+ files = project
1558
+ end
1507
1559
  files.map { |val| val == '.' ? '.' : shell_quote(basepath(val.strip)) }
1508
1560
  end
1509
1561
 
@@ -1716,7 +1768,8 @@ module Squared
1716
1768
 
1717
1769
  def session_arg?(*list, target: @session, value: false)
1718
1770
  list.any? do |val|
1719
- target.any? { |opt| opt.match?(/^#{Regexp.escape(shell_option(val))}#{value ? '[ =].' : '(?:[ =]|$)'}/o) }
1771
+ pat = /^#{Regexp.escape(shell_option(val))}#{value ? '[ =].' : '(?:[ =]|$)'}/
1772
+ target.any? { |opt| opt.match?(pat) }
1720
1773
  end
1721
1774
  end
1722
1775
 
@@ -1741,14 +1794,36 @@ module Squared
1741
1794
  end
1742
1795
  end
1743
1796
 
1797
+ def banner?
1798
+ ARG[:BANNER] && !env('BANNER', equals: '0')
1799
+ end
1800
+
1744
1801
  def stdin?
1745
1802
  pipe == 0
1746
1803
  end
1747
1804
 
1805
+ def stdout?
1806
+ !!verbose && !stdin?
1807
+ end
1808
+
1748
1809
  def warning?
1749
1810
  workspace.warning
1750
1811
  end
1751
1812
 
1813
+ def has_value?(data, val)
1814
+ return data.value?(val) if data.is_a?(::Hash)
1815
+ return data.is_a?(::Enumerable) && data.to_a.include?(val) if !val.is_a?(::Enumerable) || val.is_a?(::Hash)
1816
+
1817
+ val.to_a.any? do |obj|
1818
+ case data
1819
+ when ::Hash
1820
+ data.value?(obj)
1821
+ when ::Enumerable
1822
+ data.to_a.include?(obj)
1823
+ end
1824
+ end
1825
+ end
1826
+
1752
1827
  def variables
1753
1828
  Base.tasks + VAR_SET
1754
1829
  end