squared 0.4.3 → 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.
@@ -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,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 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.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
- if (key = target.find { |opt| opt.match?(/^#{Regexp.escape(shell_option(val))}(?: |=|$)/o) })
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 bare.include?(opt)
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] ||= 'not used'
1183
- warn log_message(Logger::WARN, opts.join(', '), pass: true, **kwargs) unless opts.empty?
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 && verbose && !stdin?
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 && ARG[: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('invalid JSON object', val, hint: hint) unless ret.is_a?(Hash)
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[key]
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(/^#{Regexp.escape(File.join(path, ''))}/o, '') : val.to_s
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
- files = files.select { |val| projectpath?(val) } unless parent
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
- target.any? { |opt| opt.match?(/^#{Regexp.escape(shell_option(val))}#{value ? '[ =].' : '(?:[ =]|$)'}/o) }
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