squared 0.6.1 → 0.6.3

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.
@@ -3,6 +3,8 @@
3
3
  require 'json'
4
4
  require 'logger'
5
5
 
6
+ require_relative 'support/class'
7
+
6
8
  module Squared
7
9
  module Workspace
8
10
  module Project
@@ -109,11 +111,11 @@ module Squared
109
111
 
110
112
  subtasks({
111
113
  'graph' => %i[run print].freeze,
112
- 'unpack' => %i[zip gz tar ext].freeze,
114
+ 'unpack' => %i[zip gz tar ext],
113
115
  'asdf' => %i[set exec current update latest where reshim]
114
116
  })
115
117
 
116
- attr_reader :name, :project, :workspace, :path, :theme, :group, :parent, :dependfile,
118
+ attr_reader :name, :project, :workspace, :path, :theme, :group, :parent, :children, :dependfile,
117
119
  :exception, :pipe, :verbose, :global
118
120
 
119
121
  def initialize(workspace, path, name, *, group: nil, first: {}, last: {}, error: {}, common: ARG[:COMMON],
@@ -380,11 +382,7 @@ module Squared
380
382
  if flag == :run
381
383
  graph args
382
384
  else
383
- out, done = graph(args, out: [])
384
- out.map! do |val|
385
- n = done.index { |proj| val.match?(/ #{Regexp.escape(proj.name)}(?:@\d|\z)/) }
386
- n ? val.subhint(n.succ) : val
387
- end
385
+ out = graph(args, out: [], order: {})
388
386
  emphasize(out, title: path, right: true, border: borderstyle, sub: [
389
387
  opt_style(theme[:header], /\A(#{Regexp.escape(path.to_s)})(.*)\z/),
390
388
  opt_style(theme[:active], /\A(#{Regexp.escape(name)})(.*)\z/),
@@ -491,7 +489,7 @@ module Squared
491
489
  proj = self
492
490
  instance_eval(&blk) if block_given?
493
491
  end
494
- @children << proj
492
+ children << proj
495
493
  end
496
494
  self
497
495
  end
@@ -553,31 +551,31 @@ module Squared
553
551
  cmd = cmd.join(' && ')
554
552
  else
555
553
  cmd, opts, var, flags, extra = args
556
- end
557
- if cmd
558
- return run_b(cmd, sync: sync, from: from) if cmd.is_a?(Proc) || cmd.is_a?(Method)
559
-
560
- cmd = as_get cmd, from
561
- opts = compose(opts, script: false) if opts && respond_to?(:compose)
562
- flags = append_hash(flags, target: []).join(' ') if flags.is_a?(Hash)
563
- case opts
564
- when Hash
565
- cmd = Array(cmd).push(flags)
566
- .concat(append_hash(opts, target: [], build: true))
567
- .compact
568
- .join(' ')
569
- when Enumerable
570
- cmd = Array(cmd).concat(opts.to_a)
571
- cmd.map! { |val| "#{val} #{flags}" } if flags
572
- cmd = cmd.join(' && ')
554
+ if cmd
555
+ return run_b(cmd, sync: sync, from: from) if cmd.is_a?(Proc) || cmd.is_a?(Method)
556
+
557
+ cmd = as_get cmd, from
558
+ opts = compose(opts, script: false) if opts && respond_to?(:compose)
559
+ flags = append_hash(flags, target: []).join(' ') if flags.is_a?(Hash)
560
+ cmd = case opts
561
+ when Hash
562
+ Array(cmd).push(flags)
563
+ .concat(append_hash(opts, target: [], build: true))
564
+ .compact
565
+ .join(' ')
566
+ when Enumerable
567
+ cmd = Array(cmd).concat(opts.to_a)
568
+ cmd.map! { |val| "#{val} #{flags}" } if flags
569
+ cmd.join(' && ')
570
+ else
571
+ [cmd, flags, opts].compact.join(' ')
572
+ end
573
573
  else
574
- cmd = [cmd, flags, opts].compact.join(' ') if opts || flags
575
- end
576
- else
577
- return unless (opts || extra) && respond_to?(:compose)
574
+ return unless (opts || extra) && respond_to?(:compose)
578
575
 
579
- cmd = compose(as_get(opts, from), flags, script: true, args: extra, from: from)
580
- from = :script if from == :run && script?
576
+ cmd = compose(as_get(opts, from), flags, script: true, args: extra, from: from)
577
+ from = :script if from == :run && script?
578
+ end
581
579
  end
582
580
  run(cmd, var, sync: sync, banner: banner, from: from)
583
581
  end
@@ -596,12 +594,12 @@ module Squared
596
594
  if proj.respond_to?(meth.to_sym)
597
595
  begin
598
596
  proj.__send__(meth, sync: sync)
599
- next
600
597
  rescue StandardError => e
601
598
  on_error(e, :prereqs, exception: true)
602
599
  end
600
+ else
601
+ print_error(name, "method: #{meth}", subject: 'prereqs', hint: 'undefined')
603
602
  end
604
- print_error(name, 'method not found', subject: 'prereqs', hint: meth)
605
603
  end
606
604
  elsif proj.build?
607
605
  proj.build(sync: sync)
@@ -618,7 +616,7 @@ module Squared
618
616
  end
619
617
 
620
618
  def doc(*, sync: invoked_sync?('doc'), **)
621
- run_b(@doc, sync: sync, banner: from_base?('doc') ? verbose? : verbosetype > 0, from: :doc)
619
+ run_b(@doc, sync: sync, banner: from_base?('doc') ? verbose? : !silent?, from: :doc)
622
620
  end
623
621
 
624
622
  def lint(*, sync: invoked_sync?('lint'), **)
@@ -659,7 +657,7 @@ module Squared
659
657
  entry = basepath(val = val.to_s)
660
658
  if entry.directory? && val.match?(%r{[\\/]\z})
661
659
  log&.warn "rm -rf #{entry}"
662
- rm_rf(entry, verbose: verbosetype > 0)
660
+ rm_rf(entry, verbose: !silent?)
663
661
  else
664
662
  log&.warn "rm #{entry}"
665
663
  (val.include?('*') ? Dir[entry] : [entry]).each do |file|
@@ -678,7 +676,7 @@ module Squared
678
676
  on :last, :clean unless pass
679
677
  end
680
678
 
681
- def graph(start = [], tasks = nil, *, sync: invoked_sync?('graph'), pass: [], out: nil, **)
679
+ def graph(start = [], tasks = nil, *, sync: invoked_sync?('graph'), pass: [], out: nil, order: nil, **)
682
680
  env('GRAPH', strict: true) do |val|
683
681
  tasks ||= []
684
682
  split_escape(val) do |task|
@@ -696,12 +694,19 @@ module Squared
696
694
  data[name] << self
697
695
  on :first, :graph
698
696
  end
699
- ret = graph_branch(self, data, tasks, out, sync: sync, pass: pass)
697
+ ret = graph_branch(self, data, tasks, out, sync: sync, pass: pass, order: order)
700
698
  rescue StandardError => e
701
699
  on_error(e, :graph, exception: true)
702
700
  else
703
701
  if out
704
- [out, ret]
702
+ if order
703
+ out.map! do |val|
704
+ name = ret.find { |proj| val.match?(/ #{Regexp.escape(proj.name)}(?:@\d|\z)/) }&.name
705
+ (n = name && order[name]) ? val.subhint(n.succ) : val
706
+ end
707
+ else
708
+ [out, ret]
709
+ end
705
710
  else
706
711
  on :last, :graph
707
712
  end
@@ -770,7 +775,7 @@ module Squared
770
775
  break uri = url if data
771
776
  end
772
777
  unless data && (ext ||= URI.decode_www_form_component(URI.parse(uri).path[/\.([\w%]+)(?:\?|\z)/, 1]))
773
- raise_error(data ? TypeError : RuntimeError, "no content#{data ? ' type' : ''}", hint: uri)
778
+ raise_error(data ? TypeError : RuntimeError, "no content#{' type' if data}", hint: uri)
774
779
  end
775
780
  end
776
781
  ext = ext.downcase
@@ -800,7 +805,7 @@ module Squared
800
805
  when 'zip', 'aar'
801
806
  session 'unzip', shell_quote(file), quote_option('d', target)
802
807
  when 'tar', /\A(?:t|tar\.)?[gx]z\z/
803
- flags = +(verbose ? 'v' : '')
808
+ flags = +(silent? ? '' : 'v')
804
809
  if ext.end_with?('gz')
805
810
  flags += 'z'
806
811
  elsif ext.end_with?('xz')
@@ -865,7 +870,7 @@ module Squared
865
870
  cmd << name
866
871
  else
867
872
  cmd << name
868
- banner = flag == :update || flag == :reshim
873
+ banner = false if flag == :latest || flag == :where
869
874
  end
870
875
  success?(run(banner: banner, from: :"asdf:#{flag}"), flag == :set || flag == :reshim)
871
876
  end
@@ -918,16 +923,16 @@ module Squared
918
923
 
919
924
  cmd = cmd.target if cmd.is_a?(OptionPartition)
920
925
  if interactive && sync && (!@session || !option('y'))
921
- title, y, hint = case interactive
922
- when Array
923
- interactive
924
- when String
925
- [interactive, 'N']
926
- else
927
- ['Run', 'Y']
928
- end
929
- title = "#{title} #{sub_style(hint, styles: theme[:active])}" if hint
930
- exit 1 unless confirm_basic("#{title}?", cmd, y)
926
+ msg, y, h = case interactive
927
+ when Array
928
+ interactive
929
+ when String
930
+ [interactive, 'N']
931
+ else
932
+ %w[Run Y]
933
+ end
934
+ msg = "#{msg} #{sub_style(h, theme[:active])}" if h
935
+ exit 1 unless confirm_basic("#{msg}?", cmd, y)
931
936
  end
932
937
  cmd = session_done cmd
933
938
  log&.info cmd
@@ -1023,6 +1028,8 @@ module Squared
1023
1028
  end
1024
1029
 
1025
1030
  def exist?(*args)
1031
+ return false if (args = args.compact).empty?
1032
+
1026
1033
  basepath(*args).exist?
1027
1034
  end
1028
1035
 
@@ -1083,6 +1090,10 @@ module Squared
1083
1090
  @prod != false && workspace.prod?(pat: @prod, **scriptargs)
1084
1091
  end
1085
1092
 
1093
+ def empty?
1094
+ children.empty?
1095
+ end
1096
+
1086
1097
  def exclude?(*refs)
1087
1098
  !@exclude.empty? && has_value?(@exclude, refs.flatten)
1088
1099
  end
@@ -1157,7 +1168,7 @@ module Squared
1157
1168
  log_console(*args, pipe: kwargs[:pipe] || pipe)
1158
1169
  end
1159
1170
 
1160
- def run_s(*cmd, sync: true, banner: verbosetype > 0, from: nil, **kwargs)
1171
+ def run_s(*cmd, sync: true, banner: !silent?, from: nil, **kwargs)
1161
1172
  cmd.flatten!
1162
1173
  case cmd.last
1163
1174
  when Hash, TrueClass, FalseClass
@@ -1202,11 +1213,11 @@ module Squared
1202
1213
  end
1203
1214
  end
1204
1215
 
1205
- def graph_branch(target, data, tasks = nil, out = nil, sync: true, pass: [], done: [], depth: 0,
1216
+ def graph_branch(target, data, tasks = nil, out = nil, sync: true, pass: [], done: [], order: nil, depth: 0,
1206
1217
  single: false, last: false, context: nil)
1207
- tag = ->(proj) { "#{proj.name}#{SEM_VER.match?(proj.version) ? "@#{proj.version}" : ''}" }
1218
+ tag = ->(proj) { "#{proj.name}#{"@#{proj.version}" if SEM_VER.match?(proj.version)}" }
1208
1219
  script = ->(proj) { workspace.script_get(:graph, group: proj.group, ref: proj.allref)&.fetch(:graph, nil) }
1209
- dedupe = lambda do |name|
1220
+ uniq = lambda do |name|
1210
1221
  next [] unless (ret = data[name])
1211
1222
 
1212
1223
  ret.dup.each do |proj|
@@ -1217,7 +1228,7 @@ module Squared
1217
1228
  ret
1218
1229
  end
1219
1230
  if depth == 0
1220
- items = dedupe.call(target.name) - done
1231
+ items = uniq.call(target.name) - done
1221
1232
  single = items.size == 1
1222
1233
  else
1223
1234
  items = data[target.name] - done
@@ -1241,7 +1252,7 @@ module Squared
1241
1252
  items.each_with_index do |proj, i|
1242
1253
  next if done.include?(proj)
1243
1254
 
1244
- t = dedupe.call(name = proj.name)
1255
+ t = uniq.call(name = proj.name)
1245
1256
  j = if out
1246
1257
  if i == items.size.pred || (post = items[i.succ..-1] - done).empty?
1247
1258
  true
@@ -1250,10 +1261,41 @@ module Squared
1250
1261
  end
1251
1262
  end
1252
1263
  unless target.name == name || (none = (t - done).empty?)
1253
- graph_branch(proj, data, tasks, out, sync: sync, pass: pass, done: done, depth: depth.succ,
1264
+ graph_branch(proj, data, tasks, out, sync: sync, pass: pass, done: done, order: order, depth: depth.succ,
1254
1265
  single: single, last: j == true, context: target)
1255
1266
  end
1256
- if !out
1267
+ if out
1268
+ if none
1269
+ a, b, c, d = ARG[:GRAPH]
1270
+ out << if depth == 0
1271
+ "#{i == items.size.pred ? d : c}#{b * 4} #{tag.call(proj)}"
1272
+ else
1273
+ s = +''
1274
+ k = 0
1275
+ final = data.keys.last
1276
+ while k < depth
1277
+ indent = k > 0 ? ((last && !j) || (j && k == depth.pred) || single) : j && last && depth == 1
1278
+ s += "#{indent || (last && data[final].last == context) ? ' ' : a} "
1279
+ k += 1
1280
+ end
1281
+ s += "#{j ? d : c}#{b * 3} #{tag.call(proj)}"
1282
+ end
1283
+ end
1284
+ if order
1285
+ n = order.size
1286
+ order[name] ||= if proj.parent
1287
+ if order[s = proj.parent.name]
1288
+ order[s] += 1
1289
+ n.pred
1290
+ else
1291
+ order[s] = n.succ
1292
+ n
1293
+ end
1294
+ else
1295
+ n
1296
+ end
1297
+ end
1298
+ else
1257
1299
  (tasks || (subtasks = script.call(proj)) || (dev? ? %w[build copy] : %w[depend build])).each do |meth|
1258
1300
  next if pass.include?(meth)
1259
1301
 
@@ -1269,21 +1311,6 @@ module Squared
1269
1311
  proj.__send__(meth.to_sym, sync: sync)
1270
1312
  end
1271
1313
  end
1272
- elsif none
1273
- a, b, c, d = ARG[:GRAPH]
1274
- out << if depth == 0
1275
- "#{i == items.size.pred ? d : c}#{b * 4} #{tag.call(proj)}"
1276
- else
1277
- s = ''.dup
1278
- k = 0
1279
- final = data.keys.last
1280
- while k < depth
1281
- indent = k > 0 ? ((last && !j) || (j && k == depth.pred) || single) : j && last && depth == 1
1282
- s += "#{indent || (last && data[final].last == context) ? ' ' : a} "
1283
- k += 1
1284
- end
1285
- s + "#{j ? d : c}#{b * 3} #{tag.call(proj)}"
1286
- end
1287
1314
  end
1288
1315
  done << proj
1289
1316
  end
@@ -1299,16 +1326,22 @@ module Squared
1299
1326
  obj.enabled? ? [obj] : []
1300
1327
  else
1301
1328
  workspace.find(group: val, ref: val.to_sym)
1329
+ end.sort do |a, b|
1330
+ if a.parent == b
1331
+ -1
1332
+ else
1333
+ b.parent == a ? 1 : 0
1334
+ end
1302
1335
  end.each do |proj|
1303
1336
  next if pass.include?(name = proj.name)
1304
1337
 
1305
1338
  if proj.graph? && !data.key?(name) && !root.include?(name)
1306
1339
  graph_collect(proj, data: data, pass: pass, root: root + [name, target.name])
1307
1340
  end
1308
- unless (objs = data.fetch(name, [])).include?(target)
1309
- deps << proj
1310
- deps.concat(objs)
1311
- end
1341
+ next if (objs = data.fetch(name, [])).include?(target)
1342
+
1343
+ deps << proj
1344
+ deps.concat(objs)
1312
1345
  end
1313
1346
  end
1314
1347
  deps.uniq!
@@ -1344,11 +1377,13 @@ module Squared
1344
1377
  ENV[name] || ENV.fetch(key, '')
1345
1378
  end
1346
1379
  if !equals.nil?
1347
- ret = ret == equals.to_s
1380
+ ret = Array(equals).any? { |val| ret == val.to_s }
1348
1381
  elsif ret.empty? || (ignore && Array(ignore).any? { |val| ret == val.to_s })
1349
1382
  ret = default
1350
1383
  end
1351
- block_given? && !ret.nil? ? yield(ret) : ret
1384
+ return yield ret if block_given? && !ret.nil?
1385
+
1386
+ ret
1352
1387
  end
1353
1388
 
1354
1389
  def session(*cmd, prefix: cmd.first, main: true, path: true, options: true)
@@ -1359,14 +1394,16 @@ module Squared
1359
1394
  ret = JoinSet.new(cmd.flatten(1))
1360
1395
  if options
1361
1396
  env("#{prefix.upcase}_OPTIONS") do |val|
1362
- if val.start_with('-')
1363
- ret.concat(shell_parse(val))
1397
+ if val.start_with?('-')
1398
+ ret.merge(shell_parse(val))
1364
1399
  else
1365
- split_escape(val) { |opt| ret.last(fill_option(opt), /\A(--?[^= ]+)[= ].+\z/m) }
1400
+ split_escape(val) { |opt| ret.last(fill_option(opt), /\A(--?[^=\s-][^=\s]*)[=\s].+\z/m) }
1366
1401
  end
1367
1402
  end
1368
1403
  end
1369
- main ? @session = ret : ret
1404
+ return ret unless main
1405
+
1406
+ @session = ret
1370
1407
  end
1371
1408
 
1372
1409
  def session_output(*cmd, **kwargs)
@@ -1495,7 +1532,7 @@ module Squared
1495
1532
  val
1496
1533
  end
1497
1534
  end
1498
- (lines << sub_style(ARG[:BORDER][1] * n, styles: border)).join("\n")
1535
+ (lines << sub_style(ARG[:BORDER][1] * n, border)).join("\n")
1499
1536
  end
1500
1537
 
1501
1538
  def print_footer(*lines, sub: nil, reverse: false, right: false, border: borderstyle, **)
@@ -1503,30 +1540,32 @@ module Squared
1503
1540
  sub = as_a sub
1504
1541
  lines.map! do |val|
1505
1542
  s = right ? val.rjust(n) : val.ljust(n)
1506
- sub.each { |h| s = sub_style(s, **h) }
1543
+ sub.each { |h| sub_style!(s, **h) }
1507
1544
  s
1508
1545
  end
1509
- [sub_style(ARG[:BORDER][1] * n, styles: border)].concat(lines)
1510
- .tap { |ret| ret.reverse! if reverse }
1511
- .join("\n")
1546
+ [sub_style(ARG[:BORDER][1] * n, border)].concat(lines)
1547
+ .tap { |ret| ret.reverse! if reverse }
1548
+ .join("\n")
1512
1549
  end
1513
1550
 
1514
1551
  def print_status(*args, from: nil, **kwargs)
1515
- return if stdin?
1552
+ return if stdin? || silent?
1516
1553
 
1517
1554
  case from
1518
1555
  when :outdated
1519
1556
  out = print_footer("major #{args[0]} / minor #{args[1]} / patch #{args[2]}", right: true).split("\n")
1520
- out[1] = sub_style(out[1], **opt_style(theme[:major], /^( +major )(\d+)(.+)$/, 2))
1521
- out[1] = sub_style(out[1], **opt_style(theme[:active], /^(.+)(minor )(\d+)(.+)$/, 3))
1522
- out[1] = sub_style(out[1], **opt_style(theme[:current], /^(.+)(patch )(\d+)(.+)$/, 3)) if theme[:current]
1523
- puts out
1557
+ sub_style!(out[1], **opt_style(theme[:major], /^( +major )(\d+)(.+)$/, 2))
1558
+ sub_style!(out[1], **opt_style(theme[:active], /^(.+)(minor )(\d+)(.+)$/, 3))
1559
+ sub_style!(out[1], **opt_style(theme[:current], /^(.+)(patch )(\d+)(.+)$/, 3)) if theme[:current]
1524
1560
  when :completed
1525
- return unless verbose && kwargs[:start]
1561
+ return unless kwargs[:start]
1526
1562
 
1527
- puts log_message(Logger::INFO, *args, sub_style('completed', styles: theme[:active]),
1528
- subject: kwargs[:subject], hint: time_format(time_epoch - kwargs[:start]))
1563
+ out = log_message(Logger::INFO, *args, sub_style('completed', theme[:active]),
1564
+ subject: kwargs[:subject], hint: time_format(time_epoch - kwargs[:start]))
1565
+ else
1566
+ return
1529
1567
  end
1568
+ puts out
1530
1569
  end
1531
1570
 
1532
1571
  def format_desc(action, flag, opts = nil, **kwargs)
@@ -1619,7 +1658,7 @@ module Squared
1619
1658
  end
1620
1659
 
1621
1660
  def empty_status(msg, title, obj, always: false)
1622
- "#{msg}#{!always && (!obj || obj == 0 || obj.to_s.empty?) ? '' : message(hint: message(title, obj.to_s))}"
1661
+ "#{msg}#{message(hint: message(title, obj.to_s)) unless !always && (!obj || obj == 0 || obj.to_s.empty?)}"
1623
1662
  end
1624
1663
 
1625
1664
  def append_repeat(flag, opts, target: @session)
@@ -1699,11 +1738,12 @@ module Squared
1699
1738
  **kwargs)
1700
1739
  return if list.empty?
1701
1740
 
1741
+ kwargs[:ignore] = false if no && !kwargs.key?(:ignore)
1702
1742
  [].tap do |ret|
1703
1743
  list.flatten.each do |flag|
1704
1744
  next unless (val = option(flag, target: target, **kwargs))
1705
1745
 
1706
- if val == '0' && no
1746
+ if no && val == '0'
1707
1747
  flag = "no-#{flag}"
1708
1748
  val = nil
1709
1749
  end
@@ -1804,6 +1844,12 @@ module Squared
1804
1844
  print_error(e, subject: name)
1805
1845
  end
1806
1846
 
1847
+ def parse_env(key)
1848
+ env(key) do |val|
1849
+ val.start_with?('-') ? shell_parse(val) : split_escape(val).map! { |opt| fill_option(opt) }
1850
+ end || []
1851
+ end
1852
+
1807
1853
  def param_guard(action, flag, args:, key: nil, pat: nil, values: nil)
1808
1854
  if args && key
1809
1855
  val = args.fetch(key, nil)
@@ -1819,29 +1865,44 @@ module Squared
1819
1865
  end
1820
1866
 
1821
1867
  def confirm_basic(msg, target, default = 'Y', style: :inline, **kwargs)
1822
- confirm("#{msg} [#{sub_style(target.to_s, styles: theme[style])}]", default, **kwargs)
1868
+ confirm("#{msg} [#{sub_style(target.to_s, theme[style])}]", default, **kwargs)
1823
1869
  end
1824
1870
 
1825
- def confirm_outdated(pkg, ver, rev, cur = nil, lock: false, col1: 0, **kwargs)
1826
- a = sub_style(case rev
1871
+ def confirm_outdated(pkg, ver, rev, cur = nil, lock: false, col0: 0, col1: 0, col2: nil, col3: 0, col4: 0,
1872
+ **kwargs)
1873
+ h = sub_style(case rev
1827
1874
  when 1
1828
1875
  'MAJOR'
1829
1876
  when 2
1830
1877
  'MINOR'
1831
1878
  else
1832
1879
  'PATCH'
1833
- end, styles: (rev == 1 && theme[:major]) || theme[:header])
1834
- b = sub_style(pkg.ljust(col1), styles: theme[:inline])
1835
- c = lock ? sub_style((cur || 'locked').rjust(7), styles: color(:red)) : cur&.rjust(7)
1880
+ end, (rev == 1 && theme[:major]) || theme[:header])
1881
+ case col0
1882
+ when 0
1883
+ col0 = "#{h}: "
1884
+ when Numeric
1885
+ puts h
1886
+ col0 = ' ' * col0
1887
+ else
1888
+ puts h
1889
+ end
1890
+ b = sub_style pkg.ljust(col1), theme[:inline]
1891
+ cur ||= 'locked' if lock
1892
+ c = if cur
1893
+ cur = cur.ljust(col2 || cur.size.succ)
1894
+ lock ? sub_style(cur, color(:red)) : cur
1895
+ end
1836
1896
  d = rev == 1 || lock ? 'N' : 'Y'
1837
- confirm("#{a}: #{b}#{c} #{sub_style(ver.rjust(col1 > 0 ? 10 : 0), styles: theme[:inline])} ", d, **kwargs)
1897
+ e = "#{col0}#{b}#{c}#{sub_style(col1 > 0 ? ver.ljust(col3) : ver.rjust(ver.size.succ), theme[:inline])}"
1898
+ confirm("#{e}#{col4 > 0 ? ' ' * [col4 - e.stripstyle.size - 1, 2].max : ' '}", d, **kwargs)
1838
1899
  end
1839
1900
 
1840
1901
  def choice_index(msg, list, values: nil, accept: nil, series: false, trim: nil, column: nil, multiple: false,
1841
1902
  force: true, **kwargs)
1842
1903
  puts unless series || printfirst?
1843
1904
  ret = choice(msg, list, multiple: multiple, force: force, **kwargs).tap do |val|
1844
- next unless val.empty?
1905
+ next unless !val || val.empty?
1845
1906
 
1846
1907
  exit 1 if force
1847
1908
  return nil
@@ -1853,12 +1914,12 @@ module Squared
1853
1914
  ret = ret.first unless multiple
1854
1915
  end
1855
1916
  if accept
1856
- hint = Array(ret).map { |val| sub_style(val.to_s, styles: theme[:inline]) }.join(', ')
1917
+ hint = Array(ret).map { |val| sub_style(val.to_s, theme[:inline]) }.join(', ')
1857
1918
  accept = Array(accept).map { |val| Array(val) }
1858
1919
  ret = Array(ret) if accept.any? { |val| val[1] == true }
1859
1920
  loop do
1860
1921
  item = accept.first
1861
- c = confirm("#{item[0]}#{hint ? " [#{hint}]" : ''}", item[2] ? 'Y' : 'N')
1922
+ c = confirm("#{item[0]}#{" [#{hint}]" if hint}", item[2] ? 'Y' : 'N')
1862
1923
  if item[1] == true
1863
1924
  ret << c
1864
1925
  elsif !c
@@ -2012,7 +2073,7 @@ module Squared
2012
2073
  end
2013
2074
 
2014
2075
  def indexerror(val, list = nil)
2015
- raise_error IndexError, "requested index #{val}", hint: list && "of #{list.size}"
2076
+ raise_error IndexError, "requested index #{val}", hint: ("of #{list.size}" if list)
2016
2077
  end
2017
2078
 
2018
2079
  def indexchar
@@ -2188,7 +2249,7 @@ module Squared
2188
2249
  end
2189
2250
 
2190
2251
  def theme_set(common)
2191
- @theme = if !verbose
2252
+ @theme = if silent?
2192
2253
  {}
2193
2254
  elsif common
2194
2255
  workspace.theme
@@ -2223,7 +2284,7 @@ module Squared
2223
2284
  __send__ key
2224
2285
  end
2225
2286
  end
2226
- next if (items = @children.select { |item| item.task_include?(key) }).empty?
2287
+ next if (items = children.select { |item| item.task_include?(key) }).empty?
2227
2288
 
2228
2289
  ws.task_desc(@desc, action, 'workspace')
2229
2290
  task task_join(action, 'workspace') => items.map! { |item| task_join(item.name, action) }
@@ -2304,7 +2365,13 @@ module Squared
2304
2365
  else
2305
2366
  $?.success?
2306
2367
  end.tap do |ret|
2307
- print_success if ret && stdout? && banner? && cond.none? { |val| val == false }
2368
+ next unless cond.none? { |val| val == false }
2369
+
2370
+ if block_given?
2371
+ yield ret
2372
+ elsif ret && stdout? && banner?
2373
+ print_success
2374
+ end
2308
2375
  end
2309
2376
  end
2310
2377
 
@@ -2328,20 +2395,42 @@ module Squared
2328
2395
  verbosetype > 1
2329
2396
  end
2330
2397
 
2398
+ def silent?
2399
+ verbosetype == 0
2400
+ end
2401
+
2331
2402
  def warning?
2332
2403
  workspace.warning
2333
2404
  end
2334
2405
 
2335
2406
  def has_value?(target, *args)
2407
+ return false unless target.is_a?(Enumerable)
2408
+
2336
2409
  args = args.first if args.size == 1 && args.first.is_a?(Enumerable)
2337
2410
  case target
2338
2411
  when Hash
2339
2412
  args.is_a?(Enumerable) ? args.any? { |obj| target.value?(obj) } : target.value?(args)
2340
- when Enumerable
2341
- args.is_a?(Enumerable) ? args.any? { |obj| target.include?(obj) } : target.include?(args)
2342
2413
  else
2343
- false
2414
+ args.is_a?(Enumerable) ? args.any? { |obj| target.include?(obj) } : target.include?(args)
2415
+ end
2416
+ end
2417
+
2418
+ def has_value!(target, *args, first: false)
2419
+ return unless target.is_a?(Enumerable)
2420
+
2421
+ args = args.first if args.size == 1 && args.first.is_a?(Enumerable)
2422
+ found = false
2423
+ args.each do |val|
2424
+ if target.respond_to?(:delete?)
2425
+ found = true if target.delete?(val)
2426
+ elsif target.respond_to?(:delete)
2427
+ found = true if target.delete(val)
2428
+ elsif target.include?(val)
2429
+ found = true
2430
+ end
2431
+ break if found && first
2344
2432
  end
2433
+ target if found
2345
2434
  end
2346
2435
 
2347
2436
  def variables