squared 0.4.11 → 0.4.12

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.
@@ -212,16 +212,11 @@ module Squared
212
212
  elsif (val = log[:file])
213
213
  file = val.is_a?(String) ? Time.now.strftime(val) : "#{@name}-#{Date.today}.log"
214
214
  end
215
- if file
216
- file = (val = env('LOG_DIR')) ? @workspace.home.join(val, file) : @workspace.home + file
217
- begin
218
- file = file.realdirpath
219
- rescue StandardError => e
220
- raise if @exception
221
-
222
- file = nil
223
- warn log_message(Logger::WARN, e, pass: true) if warning?
224
- end
215
+ begin
216
+ file &&= @workspace.home.join(env('LOG_DIR', ''), file).realdirpath
217
+ rescue StandardError => e
218
+ file = nil
219
+ warn log_message(Logger::WARN, e, pass: true) if warning?
225
220
  end
226
221
  log[:progname] ||= @name
227
222
  if (val = env('LOG_LEVEL', ignore: false))
@@ -355,7 +350,7 @@ module Squared
355
350
  false
356
351
  end
357
352
  end
358
- if path.is_a?(String) && (seg = path[%r{^(.+)[\\/]\*+$}, 1])
353
+ if path.is_a?(String) && (seg = path[%r{\A(.+)[\\/]\*+\z}, 1])
359
354
  return self unless checkdir.call(path = basepath(seg))
360
355
 
361
356
  path = path.children.select { |val| checkdir.call(val) }
@@ -366,10 +361,11 @@ module Squared
366
361
  return self
367
362
  elsif !projectpath?(path = basepath(path)) || !checkdir.call(path)
368
363
  return self
369
- elsif name.is_a?(Symbol)
370
- name = name.to_s
371
- elsif !name.is_a?(String)
372
- name = nil
364
+ else
365
+ name = case name
366
+ when String, Symbol
367
+ name.to_s
368
+ end
373
369
  end
374
370
  if @withargs
375
371
  data = @withargs.dup
@@ -389,6 +385,11 @@ module Squared
389
385
  self
390
386
  end
391
387
 
388
+ def chain(*args, **kwargs)
389
+ workspace.chain(*args, project: self, **kwargs)
390
+ self
391
+ end
392
+
392
393
  def inject(obj, *args, **kwargs, &blk)
393
394
  return self unless enabled?
394
395
 
@@ -518,7 +519,7 @@ module Squared
518
519
  if @clean.is_a?(Enumerable) && !series?(@clean)
519
520
  @clean.each do |val|
520
521
  entry = path + (val = val.to_s)
521
- if entry.directory? && val.match?(%r{[\\/]$})
522
+ if entry.directory? && val.match?(%r{[\\/]\z})
522
523
  log&.warn "rm -rf #{entry}"
523
524
  rm_rf(entry, verbose: verbose)
524
525
  else
@@ -572,8 +573,7 @@ module Squared
572
573
  end
573
574
  end
574
575
 
575
- def unpack(target, uri:, sync: true, digest: nil, ext: nil, force: false, depth: 1, headers: {},
576
- from: :unpack)
576
+ def unpack(target, uri:, sync: true, digest: nil, ext: nil, force: false, depth: 1, headers: {}, from: :unpack)
577
577
  if !target.exist?
578
578
  target.mkpath
579
579
  elsif !target.directory?
@@ -581,18 +581,11 @@ module Squared
581
581
  elsif !target.empty?
582
582
  raise_error('directory not empty', hint: target) unless force || env('UNPACK_FORCE')
583
583
  create = true
584
- elsif !uri
585
- raise_error('no download uri', hint: target)
586
584
  end
587
585
  if digest
588
586
  require 'digest'
589
- if (n = digest.index(':').to_i) > 0
590
- size = digest[0, n].downcase
591
- digest = digest[n + 1..-1]
592
- else
593
- size = digest.size
594
- end
595
- algo = case size
587
+ digest, type = digest.split(':', 2).reverse
588
+ algo = case type&.downcase || digest.size
596
589
  when 32, 'md5'
597
590
  Digest::MD5
598
591
  when 'rmd160'
@@ -610,16 +603,15 @@ module Squared
610
603
  end
611
604
  end
612
605
  if (val = env('HEADERS')) && (val = parse_json(val, hint: "HEADERS_#{@envname}"))
613
- headers = val
606
+ headers = headers.is_a?(Hash) ? headers.merge(val) : val
614
607
  end
615
608
  data = nil
616
609
  (uri = as_a(uri)).each_with_index do |url, index|
617
- last = index == uri.size - 1
618
610
  fetch_uri(url, headers) do |f|
619
611
  data = f.read
620
612
  if algo && algo.hexdigest(data) != digest
621
613
  data = nil
622
- raise_error("checksum failed: #{digest}", hint: url) if last
614
+ raise_error("checksum failed: #{digest}", hint: url) if index == uri.size - 1
623
615
  end
624
616
  next if ext && index == 0
625
617
 
@@ -632,14 +624,11 @@ module Squared
632
624
  ext = 'txz'
633
625
  end
634
626
  end
635
- if data
636
- uri = url
637
- break
638
- elsif last
639
- raise_error('no content', hint: url)
640
- end
627
+ break uri = url if data
628
+ end
629
+ unless data && (ext ||= URI.parse(uri).path[/\.(\w+)(?:\?|\z)/, 1])
630
+ raise_error("no content#{data ? ' type' : ''}", hint: uri)
641
631
  end
642
- raise_error('no content type', hint: uri) unless ext ||= URI.parse(uri).path[/\.(\w+)(\?|$)/i, 1]
643
632
  ext = ext.downcase
644
633
  if (val = env("#{%w[zip 7z gem].include?(ext) ? ext.upcase : 'TAR'}_DEPTH", ignore: false))
645
634
  depth = val.to_i
@@ -698,8 +687,8 @@ module Squared
698
687
  ensure
699
688
  if dir
700
689
  remove_entry dir
701
- elsif file
702
- file.unlink
690
+ else
691
+ file&.unlink
703
692
  end
704
693
  end
705
694
  end
@@ -916,6 +905,7 @@ module Squared
916
905
  end
917
906
  return
918
907
  end
908
+ cmd = cmd.target if cmd.is_a?(OptionPartition)
919
909
  cmd = session_done cmd
920
910
  log&.info cmd
921
911
  on :first, from
@@ -1178,8 +1168,8 @@ module Squared
1178
1168
  end
1179
1169
 
1180
1170
  def print_item(*val)
1181
- puts if @@print_order > 0 && stdout?
1182
- @@print_order += 1
1171
+ puts if !printfirst? && stdout?
1172
+ printsucc
1183
1173
  puts val unless val.empty? || (val.size == 1 && val.first.nil?)
1184
1174
  end
1185
1175
 
@@ -1209,10 +1199,9 @@ module Squared
1209
1199
 
1210
1200
  def print_footer(*lines, sub: nil, reverse: false, right: false, **kwargs)
1211
1201
  n = Project.max_width(lines)
1212
- sub = as_a sub
1213
1202
  lines.map! do |val|
1214
1203
  s = right ? val.rjust(n) : val.ljust(n)
1215
- sub.each { |h| s = sub_style(s, **h) }
1204
+ sub&.each { |h| s = sub_style(s, **h) }
1216
1205
  s
1217
1206
  end
1218
1207
  ret = [sub_style(ARG[:BORDER][1] * n, styles: kwargs.key?(:border) ? kwargs[:border] : borderstyle), *lines]
@@ -1243,7 +1232,7 @@ module Squared
1243
1232
  if data[:command]
1244
1233
  if cmd =~ /\A(?:"((?:[^"]|(?<=\\)")+)"|'((?:[^']|(?<=\\)')+)'|(\S+)) /
1245
1234
  path = $3 || $2 || $1
1246
- cmd = cmd.sub(path, File.basename(path).upcase)
1235
+ cmd = cmd.sub(path, stripext(path).upcase)
1247
1236
  end
1248
1237
  out << cmd
1249
1238
  end
@@ -1502,12 +1491,12 @@ module Squared
1502
1491
  b = sub_style("#{pkg} #{ver}", styles: theme[:inline])
1503
1492
  c, d = rev == 1 || lock ? ['y/N', 'N'] : ['Y/n', 'Y']
1504
1493
  e = lock ? " #{sub_style('(locked)', styles: color(:red))}" : ''
1505
- confirm("Upgrade to #{a}? #{b + e} [#{c}] ", d)
1494
+ confirm "Upgrade to #{a}? #{b + e} [#{c}] ", d
1506
1495
  end
1507
1496
 
1508
1497
  def choice_index(msg, list, values: nil, accept: nil, series: false, trim: nil, column: nil,
1509
1498
  multiple: false, force: true, **kwargs)
1510
- puts if !series && @@print_order > 0
1499
+ puts if !series && !printfirst?
1511
1500
  msg = "#{msg} (optional)" unless force
1512
1501
  unless (ret = choice(msg, list, multiple: multiple, force: force, **kwargs)) || !force
1513
1502
  raise_error 'user cancelled'
@@ -1519,7 +1508,7 @@ module Squared
1519
1508
  end
1520
1509
  ret = multiple ? ret.map! { |val| val.sub(trim, '') } : ret.sub(trim, '') if trim
1521
1510
  if column
1522
- a, b = as_a(column)
1511
+ a, b = as_a column
1523
1512
  ret = as_a(ret).map! { |val| val[a, b || 1] }
1524
1513
  ret = ret.first unless multiple
1525
1514
  end
@@ -1554,7 +1543,7 @@ module Squared
1554
1543
  ret << (val.empty? ? nil : val)
1555
1544
  end
1556
1545
  end
1557
- @@print_order += 1 unless series
1546
+ printsucc unless series
1558
1547
  ret
1559
1548
  end
1560
1549
 
@@ -1608,15 +1597,17 @@ module Squared
1608
1597
  end
1609
1598
 
1610
1599
  def indexitem(val)
1611
- return unless val =~ /\A\^(\d+)(:.+)?\z/
1612
-
1613
- [$1.to_i, $2 && $2[1..-1]]
1600
+ [$1.to_i, $2 && $2[1..-1]] if val =~ /\A\^(\d+)(:.+)?\z/
1614
1601
  end
1615
1602
 
1616
1603
  def indexerror(val, list = nil)
1617
1604
  raise_error("requested index #{val}", hint: list && "of #{list.size}")
1618
1605
  end
1619
1606
 
1607
+ def printsucc
1608
+ @@print_order += 1
1609
+ end
1610
+
1620
1611
  def color(val)
1621
1612
  ret = theme[val]
1622
1613
  ret && !ret.empty? ? ret : [val]
@@ -1642,16 +1633,14 @@ module Squared
1642
1633
  end
1643
1634
 
1644
1635
  def on(event, from, *args, **kwargs)
1645
- return unless from
1646
-
1647
- @events[event][from]&.each do |obj|
1648
- if obj.is_a?(Array) && obj[1].is_a?(Hash)
1649
- opts = kwargs.empty? ? obj[1] : obj[1].merge(kwargs)
1650
- target = obj[0]
1651
- else
1652
- opts = kwargs
1653
- target = obj
1654
- end
1636
+ return unless from && (data = @events[event])
1637
+
1638
+ data[from]&.each do |obj|
1639
+ target, opts = if obj.is_a?(Array) && obj[1].is_a?(Hash)
1640
+ [obj[0], kwargs.empty? ? obj[1] : obj[1].merge(kwargs)]
1641
+ else
1642
+ [obj, kwargs]
1643
+ end
1655
1644
  as_a(target, flat: true).each do |cmd|
1656
1645
  case cmd
1657
1646
  when Proc, Method
@@ -1796,6 +1785,10 @@ module Squared
1796
1785
  (cur[0] == '0' && want[0] == '0' ? cur[2] != want[2] : cur[0] != want[0]) && !want[5]
1797
1786
  end
1798
1787
 
1788
+ def printfirst?
1789
+ @@print_order == 0
1790
+ end
1791
+
1799
1792
  def runnable?(val)
1800
1793
  case val
1801
1794
  when String, Enumerable, Proc, Method
@@ -1825,8 +1818,9 @@ module Squared
1825
1818
  return true if val || from_sync?(ac = workspace.task_name(action))
1826
1819
  return val if group && !(val = from_sync?(ac, group)).nil?
1827
1820
  return val if (base = workspace.find_base(self)) && !(val = from_sync?(ac, base.ref)).nil?
1821
+ return false if workspace.series.chain?(val = task_join(name, action))
1828
1822
 
1829
- if task_invoked?(task_join(name, ac)) && (!task_invoked?(ac) || !workspace.task_defined?(ac, 'sync'))
1823
+ if task_invoked?(val) && (!task_invoked?(ac) || !workspace.task_defined?(ac, 'sync'))
1830
1824
  true
1831
1825
  else
1832
1826
  val = workspace.series.name_get(action)
@@ -653,11 +653,11 @@ module Squared
653
653
  index += 1
654
654
  next unless confirm("#{h + b}? [#{c}] ", d, timeout: 60)
655
655
 
656
- puts if @@print_order == 0
656
+ puts if printfirst?
657
657
  end
658
658
  yield id
659
659
  end
660
- puts log_message(Logger::INFO, 'none detected', subject: "#{name}:#{from}", hint: hint) unless found || y
660
+ puts log_message(Logger::INFO, 'none detected', subject: "#{name}:#{from}", hint: hint) if found || y
661
661
  end
662
662
  rescue StandardError => e
663
663
  log.error e
@@ -670,13 +670,13 @@ module Squared
670
670
  def confirm_command(*args, title: nil, target: nil, as: nil)
671
671
  return false unless title && target
672
672
 
673
- puts unless @@print_order == 0
673
+ puts unless printfirst?
674
674
  t = title.to_s.split(':')
675
675
  emphasize(args, title: message(t.first.upcase, *t.drop(1)), border: borderstyle, sub: [
676
676
  { pat: /\A(\w+(?: => \w+)+)(.*)\z/, styles: theme[:header] },
677
677
  { pat: /\A(.+)\z/, styles: theme[:caution] }
678
678
  ])
679
- @@print_order += 1
679
+ printsucc
680
680
  a = t.last.capitalize
681
681
  b = sub_style(target, styles: theme[:subject])
682
682
  c = as && sub_style(as, styles: theme[:inline])
@@ -14,7 +14,11 @@ module Squared
14
14
  check = ->(proj) { proj.is_a?(Project::Git) && !proj.exclude?(Project::Git.ref) && git_clone?(proj.path) }
15
15
  if uri.is_a?(Array)
16
16
  base = name
17
- uri.each { |val| repo << proj if (proj = @project[val.to_s]) && check.call(proj) }
17
+ uri.each do |val|
18
+ if (proj = @project[val.to_s]) && check.call(proj)
19
+ repo << proj
20
+ end
21
+ end
18
22
  elsif uri
19
23
  data[name.to_s] = uri
20
24
  elsif name.is_a?(Enumerable)
@@ -121,20 +125,18 @@ module Squared
121
125
  def rev_write(name = nil, data = nil, sync: true, utc: nil)
122
126
  return unless @revfile
123
127
 
128
+ sleep 0 while !sync && @revlock
129
+ @revlock = true
124
130
  if name
125
131
  data&.each { |key, val| rev_entry(name, key, val: val) }
126
132
  rev_timeutc(name, utc) if utc
127
133
  end
128
- sleep 0 while !sync && @revlock
129
- begin
130
- @revlock = true
131
- File.write(@revfile, JSON.pretty_generate(@revdoc))
132
- rescue StandardError => e
133
- log&.debug e
134
- warn log_message(Logger::WARN, e, pass: true) if warning?
135
- ensure
136
- @revlock = false
137
- end
134
+ File.write(@revfile, JSON.pretty_generate(@revdoc))
135
+ rescue StandardError => e
136
+ log&.debug e
137
+ warn log_message(Logger::WARN, e, pass: true) if warning?
138
+ ensure
139
+ @revlock = false
138
140
  end
139
141
 
140
142
  def git_clone?(path, name = nil)
@@ -457,8 +459,8 @@ module Squared
457
459
  when 'stash'
458
460
  format_desc(action, flag, 'opts*', after: case flag
459
461
  when :push then 'pathspec*'
460
- when :list then nil
461
- else 'commit?' end)
462
+ when :clear, :list then nil
463
+ else 'stash?|:' end)
462
464
  task flag do |_, args|
463
465
  stash flag, args.to_a
464
466
  end
@@ -516,15 +518,7 @@ module Squared
516
518
  index = choice_commit(multiple: true)
517
519
  else
518
520
  index = []
519
- args.each do |val|
520
- if matchhead(val)
521
- index << commithead(val)
522
- elsif (sha = commithash(val))
523
- index << sha
524
- else
525
- break
526
- end
527
- end
521
+ args.each { |val| index << (commithead(val) || commithash(val) || break) }
528
522
  args = args.drop(index.size)
529
523
  end
530
524
  diff(flag, args, index: index)
@@ -1012,10 +1006,13 @@ module Squared
1012
1006
  when :push
1013
1007
  append_pathspec op.extras
1014
1008
  when :pop, :apply, :drop
1015
- unless op.empty?
1009
+ if op.extras.delete(':')
1010
+ op << choice_index('Choose a stash', git_spawn('stash list', stdout: false),
1011
+ column: /^[^@]+@\{(\d+)\}/, force: true)
1012
+ elsif !op.empty?
1016
1013
  op << shell_escape(op.pop)
1017
- op.clear
1018
1014
  end
1015
+ op.clear
1019
1016
  when :clear
1020
1017
  if confirm("Remove #{sub_style('all', styles: theme[:active])} stash entries? [y/N] ", 'N')
1021
1018
  source(stdout: true)
@@ -1064,7 +1061,7 @@ module Squared
1064
1061
  { pat: /^(## )(.+?)(\.{3})(.+)$/, styles: [nil, g, nil, r], index: -1 }
1065
1062
  ]
1066
1063
  else
1067
- [{ pat: /^(\t+)([a-z]+: +.+)$/, styles: r, index: 2 }]
1064
+ [pat: /^(\t+)([a-z]+: +.+)$/, styles: r, index: 2]
1068
1065
  end
1069
1066
  end
1070
1067
  out, banner, from = source(io: true)
@@ -1072,7 +1069,7 @@ module Squared
1072
1069
  list_result(ret, 'files', from: from, action: 'modified')
1073
1070
  end
1074
1071
 
1075
- def revbuild(flag = nil, opts = [], sync: invoked_sync?('revbuild', flag), **kwargs)
1072
+ def revbuild(flag = nil, opts = [], sync: nil, **kwargs)
1076
1073
  statusargs = lambda do
1077
1074
  {
1078
1075
  include: relativepath(as_a(kwargs[:include]), all: true),
@@ -1090,6 +1087,7 @@ module Squared
1090
1087
  sha = git_spawn('rev-parse --verify HEAD').chomp
1091
1088
  return if sha.empty?
1092
1089
 
1090
+ sync = invoked_sync?('revbuild', flag) if sync.nil?
1093
1091
  kwargs = kwargs.key?(:include) || kwargs.key?(:exclude) ? statusargs.call : @revbuild || {}
1094
1092
  case flag
1095
1093
  when :build
@@ -1457,7 +1455,7 @@ module Squared
1457
1455
  else
1458
1456
  git_spawn 'fetch --all --prune --quiet' if option('sync')
1459
1457
  out, banner, from = source(cmd << '-vv --no-abbrev --list', io: true)
1460
- ret = write_lines(out, grep: /^\*\s+#{Regexp.escape(head)}\s/, banner: banner, first: true) do |line|
1458
+ ret = write_lines(out, grep: [/^\*\s+#{Regexp.escape(head)}\s/], banner: banner, first: true) do |line|
1461
1459
  next line if stdin?
1462
1460
 
1463
1461
  data = line.sub(/^\*\s+/, '').split(/\s+/)
@@ -1585,7 +1583,7 @@ module Squared
1585
1583
  op << shell_quote(remote) if remote
1586
1584
  out, banner, from = source(io: true)
1587
1585
  print_item banner
1588
- ret = write_lines(out, grep: op.extras)
1586
+ ret = write_lines(out, grep: op.extras, prefix: "refs/#{flag}/")
1589
1587
  list_result(ret, flag.to_s, from: from, grep: op.extras)
1590
1588
  end
1591
1589
 
@@ -1662,7 +1660,7 @@ module Squared
1662
1660
  def source(cmd = @session, exception: true, io: false, sync: true, stdout: false, stderr: false, banner: true,
1663
1661
  multiple: false, **kwargs)
1664
1662
  cmd = cmd.target if cmd.is_a?(OptionPartition)
1665
- banner = nil if multiple && banner
1663
+ banner = nil if banner && (multiple || !banner?)
1666
1664
  if cmd.respond_to?(:done)
1667
1665
  if io && banner == false
1668
1666
  from = nil
@@ -1723,15 +1721,27 @@ module Squared
1723
1721
  end
1724
1722
  end
1725
1723
 
1726
- def write_lines(data, banner: nil, loglevel: nil, grep: nil, sub: nil, pass: false, first: false)
1727
- grep &&= as_a(grep).yield_self { |a| a.empty? || a.include?('*') ? nil : a.map { |val| Regexp.new(val) } }
1728
- sub &&= stdin? ? nil : as_a(sub)
1724
+ def write_lines(data, grep: [], prefix: nil, sub: nil, banner: nil, loglevel: nil, pass: false, first: false)
1725
+ grep = unless grep.empty?
1726
+ grep.map do |val|
1727
+ if val.is_a?(Regexp)
1728
+ val
1729
+ else
1730
+ val = ".*#{val}" if prefix && !val.sub!(/\A(\^|\\A)/, '')
1731
+ Regexp.new("#{prefix}#{val == '*' ? '.+' : val}")
1732
+ end
1733
+ end
1734
+ end
1735
+ sub = nil if stdin?
1729
1736
  ret = 0
1730
1737
  out = []
1731
1738
  data.each do |line|
1732
1739
  next if grep&.none? { |pat| pat.match?(line) }
1733
1740
 
1734
- line = yield line if block_given?
1741
+ if block_given?
1742
+ line = yield line
1743
+ next unless line
1744
+ end
1735
1745
  if loglevel
1736
1746
  log&.add loglevel, line
1737
1747
  else
@@ -1749,20 +1759,15 @@ module Squared
1749
1759
  ret
1750
1760
  end
1751
1761
 
1752
- def list_result(size, type, from: nil, action: 'found', grep: nil)
1762
+ def list_result(size, type, grep: [], action: 'found', from: nil)
1753
1763
  if verbose
1754
1764
  if size > 0
1755
1765
  styles = theme.fetch(:banner, []).reject { |s| s.to_s.end_with?('!') }
1756
1766
  styles << :bold if styles.size <= 1
1757
1767
  puts print_footer("#{size} #{size == 1 ? type.sub(/(?:(?<!l)e)?s\z/, '') : type}",
1758
- sub: { pat: /^(\d+)(.+)$/, styles: styles })
1768
+ sub: [pat: /^(\d+)(.+)$/, styles: styles])
1759
1769
  else
1760
- puts empty_status("No #{type} were #{action}", 'grep', grep.is_a?(Array) ? case grep.size
1761
- when 0
1762
- nil
1763
- else
1764
- grep.join(', ')
1765
- end : grep.to_s)
1770
+ puts empty_status("No #{type} were #{action}", 'grep', grep.join(', '))
1766
1771
  end
1767
1772
  end
1768
1773
  on :last, from
@@ -1843,7 +1848,7 @@ module Squared
1843
1848
  when 'refspec'
1844
1849
  refspec << shell_escape($2, quote: true)
1845
1850
  end
1846
- elsif op.arg?('--multiple')
1851
+ elsif op.arg?('multiple')
1847
1852
  op.found << opt
1848
1853
  else
1849
1854
  op.errors << opt
@@ -1858,7 +1863,7 @@ module Squared
1858
1863
  op.merge(refspec)
1859
1864
  end
1860
1865
  op.delete('--all')
1861
- elsif op.arg?('--multiple')
1866
+ elsif op.arg?('multiple')
1862
1867
  op.swap.merge(op.map! { |opt| shell_escape(opt, quote: true) })
1863
1868
  return
1864
1869
  elsif option('all')
@@ -1975,7 +1980,7 @@ module Squared
1975
1980
  end
1976
1981
 
1977
1982
  def commithash(val)
1978
- val[/:(\h{5,40})\z/, 1] || val[/\A#\{(\h{5,40})\}\z/, 1]
1983
+ val[/\A:(\h{5,40})\z/, 1] || val[/\A#\{(\h{5,40})\}\z/, 1]
1979
1984
  end
1980
1985
 
1981
1986
  def commithead(val)