squared 0.5.1 → 0.5.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.
@@ -9,7 +9,6 @@ module Squared
9
9
  module Workspace
10
10
  module Project
11
11
  class Base
12
- include Comparable
13
12
  include Common::Format
14
13
  include System
15
14
  include Shell
@@ -17,9 +16,10 @@ module Squared
17
16
  include Utils
18
17
  include Support
19
18
  include Rake::DSL
19
+ include ::Comparable
20
20
 
21
21
  VAR_SET = %i[parent global script index envname desc dependfile dependindex theme archive env dev prod graph
22
- pass exclude].freeze
22
+ pass only exclude].freeze
23
23
  BLK_SET = %i[run depend doc lint test copy clean].freeze
24
24
  SEM_VER = /\b(\d+)(?:(\.)(\d+))?(?:(\.)(\d+)(\S+)?)?\b/.freeze
25
25
  URI_SCHEME = %r{^([a-z][a-z\d+-.]*)://[^@:\[\]\\^<>|\s]}i.freeze
@@ -73,8 +73,8 @@ module Squared
73
73
  'unpack' => %i[zip tar gem ext].freeze
74
74
  })
75
75
 
76
- attr_reader :name, :project, :workspace, :path, :theme, :exception, :pipe, :verbose,
77
- :group, :parent, :dependfile
76
+ attr_reader :name, :project, :workspace, :path, :theme, :group, :parent, :dependfile,
77
+ :exception, :pipe, :verbose
78
78
 
79
79
  def initialize(workspace, path, name, *, group: nil, first: {}, last: {}, error: {}, common: ARG[:COMMON],
80
80
  **kwargs)
@@ -89,16 +89,15 @@ module Squared
89
89
  @test = kwargs[:test]
90
90
  @copy = kwargs[:copy]
91
91
  @clean = kwargs[:clean]
92
- @version = kwargs[:version]
93
92
  @release = kwargs[:release]
93
+ self.version = kwargs[:version]
94
+ self.exception = kwargs[:exception]
95
+ self.pipe = kwargs[:pipe]
96
+ self.verbose = kwargs[:verbose]
94
97
  @output = []
95
98
  @ref = []
96
99
  @children = []
97
- @events = {
98
- first: first,
99
- last: last,
100
- error: error
101
- }
100
+ @events = hashobj.update({ first: first, last: last, error: error })
102
101
  @envname = env_key(@name).freeze
103
102
  @desc = (@name.include?(':') ? @name.split(':').join(ARG[:SPACE]) : @name).freeze
104
103
  @parent = nil
@@ -110,11 +109,9 @@ module Squared
110
109
  @session = nil
111
110
  @index = -1
112
111
  run_set(kwargs[:run], kwargs[:env], opts: kwargs.fetch(:opts, true))
113
- exception_set kwargs[:exception]
114
- pipe_set kwargs[:pipe]
115
- verbose_set kwargs[:verbose]
116
112
  graph_set kwargs[:graph]
117
113
  pass_set kwargs[:pass]
114
+ only_set kwargs[:only]
118
115
  exclude_set kwargs[:exclude]
119
116
  archive_set kwargs[:archive]
120
117
  theme_set common
@@ -176,9 +173,7 @@ module Squared
176
173
  def initialize_events(ref, **)
177
174
  return unless (events = @workspace.events_get(group: @group, ref: ref))
178
175
 
179
- events.each do |task, data|
180
- data.each { |ev, blk| (@events[ev] ||= {})[task] ||= [blk] }
181
- end
176
+ events.each { |task, data| data.each { |ev, blk| @events[ev][task] ||= [blk] } }
182
177
  end
183
178
 
184
179
  def initialize_logger(log: nil, **)
@@ -243,8 +238,13 @@ module Squared
243
238
  end
244
239
  end
245
240
 
241
+ def ==(other)
242
+ equal?(other)
243
+ end
244
+
246
245
  def <=>(other)
247
- return 0 unless workspace == other.workspace
246
+ return unless workspace == other.workspace
247
+ return 0 if equal?(other)
248
248
 
249
249
  a, b = graph_deps
250
250
  return 1 if a.include?(other)
@@ -272,13 +272,34 @@ module Squared
272
272
  elsif f.any? { |val| e.include?(val) }
273
273
  1
274
274
  elsif @index >= 0 && (i = other.instance_variable_get(:@index)) >= 0
275
- @index <= i ? -1 : 1
276
- else
277
- 0
275
+ @index <=> i
278
276
  end
279
277
  rescue StandardError => e
280
278
  log&.debug e
281
- 0
279
+ nil
280
+ end
281
+
282
+ def version=(val)
283
+ @version = val&.to_s
284
+ end
285
+
286
+ def exception=(val)
287
+ @exception = env_bool(val, workspace.exception, strict: true)
288
+ end
289
+
290
+ def pipe=(val)
291
+ @pipe = env_pipe(val, workspace.pipe, strict: true)
292
+ end
293
+
294
+ def verbose=(val)
295
+ @verbose = case val
296
+ when NilClass
297
+ workspace.verbose
298
+ when String
299
+ env_bool(val, workspace.verbose, strict: true, index: true)
300
+ else
301
+ val
302
+ end
282
303
  end
283
304
 
284
305
  def ref
@@ -291,7 +312,7 @@ module Squared
291
312
 
292
313
  namespace name do
293
314
  Base.subtasks do |action, flags|
294
- next if @pass.include?(action)
315
+ next if task_pass?(action)
295
316
 
296
317
  namespace action do
297
318
  flags.each do |flag|
@@ -497,11 +518,9 @@ module Squared
497
518
  if proj.respond_to?(meth.to_sym)
498
519
  begin
499
520
  proj.__send__(meth, sync: sync)
500
- rescue StandardError => e
501
- ret = on :error, :prereqs, e
502
- raise unless ret == true
503
- else
504
521
  next
522
+ rescue StandardError => e
523
+ on_error(:prereqs, e, exception: true)
505
524
  end
506
525
  end
507
526
  warn log_message(Logger::WARN, name, 'method not found', subject: 'prereqs', hint: meth)
@@ -554,9 +573,7 @@ module Squared
554
573
  begin
555
574
  @clean.each { |cmd, opts| build(cmd.to_s, opts, sync: sync) }
556
575
  rescue StandardError => e
557
- log&.error e
558
- ret = on :error, from, e
559
- raise if exception && ret != true
576
+ on_error e, from
560
577
  end
561
578
  else
562
579
  if @clean.is_a?(Enumerable) && !series?(@clean)
@@ -605,8 +622,7 @@ module Squared
605
622
  end
606
623
  ret = graph_branch(self, data, tasks, out, sync: sync, pass: pass)
607
624
  rescue StandardError => e
608
- ret = on :error, :graph, e
609
- raise unless ret == true
625
+ on_error(:graph, e, exception: true)
610
626
  else
611
627
  if out
612
628
  [out, ret]
@@ -615,13 +631,13 @@ module Squared
615
631
  end
616
632
  end
617
633
 
618
- def unpack(target, uri:, sync: true, digest: nil, ext: nil, force: false, depth: 1, headers: {}, from: :unpack)
619
- require 'open-uri'
634
+ def unpack(target, file = nil, uri: nil, sync: true, digest: nil, ext: nil, force: false, depth: 1, headers: {},
635
+ verbose: self.verbose, from: :unpack)
620
636
  if !target.exist?
621
637
  target.mkpath
622
638
  elsif !target.directory?
623
639
  raise_error('invalid location', hint: target)
624
- elsif !target.empty?
640
+ elsif !file && !target.empty?
625
641
  raise_error('directory not empty', hint: target) unless force || env('UNPACK_FORCE')
626
642
  create = true
627
643
  end
@@ -648,44 +664,53 @@ module Squared
648
664
  if (val = env('HEADERS')) && (val = parse_json(val, hint: "HEADERS_#{@envname}"))
649
665
  headers = headers.is_a?(Hash) ? headers.merge(val) : val
650
666
  end
651
- data = nil
652
- (uri = Array(uri)).each_with_index do |url, index|
653
- URI.open(url, headers) do |f|
654
- data = f.read
655
- if algo && algo.hexdigest(data) != digest
656
- data = nil
657
- raise_error("checksum failed: #{digest}", hint: url) if index == uri.size - 1
658
- end
659
- next if ext && index == 0
660
-
661
- case f.content_type
662
- when 'application/zip'
663
- ext = 'zip'
664
- when 'application/x-gzip'
665
- ext = 'tgz'
666
- when 'application/x-xz'
667
- ext = 'txz'
667
+ if file
668
+ ext ||= File.extname(file)[1..-1]
669
+ else
670
+ require 'open-uri'
671
+ data = nil
672
+ (uri = Array(uri)).each_with_index do |url, index|
673
+ URI.open(url, headers) do |f|
674
+ data = f.read
675
+ if algo && algo.hexdigest(data) != digest
676
+ data = nil
677
+ raise_error("checksum failed: #{digest}", hint: url) if index == uri.size - 1
678
+ end
679
+ next if ext && index == 0
680
+
681
+ case f.content_type
682
+ when 'application/zip'
683
+ ext = 'zip'
684
+ when 'application/x-gzip'
685
+ ext = 'tgz'
686
+ when 'application/x-xz'
687
+ ext = 'txz'
688
+ end
668
689
  end
690
+ break uri = url if data
691
+ end
692
+ unless data && (ext ||= URI.parse(uri).path[/\.(\w+)(?:\?|\z)/, 1])
693
+ raise_error("no content#{data ? ' type' : ''}", hint: uri)
669
694
  end
670
- break uri = url if data
671
- end
672
- unless data && (ext ||= URI.parse(uri).path[/\.(\w+)(?:\?|\z)/, 1])
673
- raise_error("no content#{data ? ' type' : ''}", hint: uri)
674
695
  end
675
696
  ext = ext.downcase
676
697
  if (val = env("#{%w[zip 7z gem].include?(ext) ? ext.upcase : 'TAR'}_DEPTH", ignore: false))
677
698
  depth = val.to_i
678
699
  end
679
700
  begin
680
- if ext == 'gem'
681
- dir = Dir.mktmpdir
682
- file = File.new(File.join(dir, File.basename(uri)), 'w')
683
- else
684
- require 'tempfile'
685
- file = Tempfile.new("#{name}-")
701
+ unless file
702
+ if ext == 'gem'
703
+ dir = Dir.mktmpdir
704
+ file = File.new(File.join(dir, File.basename(uri)), 'w')
705
+ else
706
+ require 'tempfile'
707
+ file = Tempfile.new("#{name}-")
708
+ end
709
+ file.write(data)
710
+ file.close
711
+ file = Pathname.new(file)
712
+ delete = true
686
713
  end
687
- file.write(data)
688
- file.close
689
714
  if create
690
715
  warn log_message(Logger::WARN, 'force remove', subject: name, hint: target)
691
716
  target.rmtree
@@ -693,7 +718,7 @@ module Squared
693
718
  end
694
719
  case ext
695
720
  when 'zip', 'aar'
696
- session 'unzip', shell_quote(file.path), quote_option('d', target)
721
+ session 'unzip', shell_quote(file), quote_option('d', target)
697
722
  when 'tar', 'tgz', 'tar.gz', 'tar.xz', 'gz', 'xz'
698
723
  flags = +(verbose ? 'v' : '')
699
724
  if ext.end_with?('gz')
@@ -701,24 +726,24 @@ module Squared
701
726
  elsif ext.end_with?('xz')
702
727
  flags += 'J'
703
728
  end
704
- session 'tar', "-x#{flags}", basic_option('strip-components', depth), quote_option('f', file.path),
729
+ session 'tar', "-x#{flags}", basic_option('strip-components', depth), quote_option('f', file),
705
730
  quote_option('C', target)
706
731
  depth = 0
707
732
  when '7z'
708
- session '7z', 'x', shell_quote(file.path), "-o#{shell_quote(target)}"
733
+ session '7z', 'x', shell_quote(file), "-o#{shell_quote(target)}"
709
734
  when 'gem'
710
- session 'gem', 'unpack', shell_quote(file.path), quote_option('target', target)
735
+ session 'gem', 'unpack', shell_quote(file), quote_option('target', target)
711
736
  depth = 0 unless val
712
737
  else
713
- raise_error("unsupported format: #{ext}", hint: uri)
738
+ raise_error("unsupported format: #{ext}", hint: uri || file)
714
739
  end
715
- run(sync: sync, from: from)
740
+ run(sync: sync, banner: verbose, from: from)
716
741
  while depth > 0 && target.children.size == 1
717
742
  entry = target.children.first
718
743
  break unless entry.directory?
719
744
 
720
745
  i = 0
721
- while (dest = target + "#{File.basename(file.path)}-#{i}").exist?
746
+ while (dest = target + "#{File.basename(file)}-#{i}").exist?
722
747
  i += 1
723
748
  end
724
749
  FileUtils.mv(entry, dest)
@@ -730,8 +755,8 @@ module Squared
730
755
  ensure
731
756
  if dir
732
757
  remove_entry dir
733
- else
734
- file&.unlink
758
+ elsif delete && file&.exist?
759
+ file.unlink
735
760
  end
736
761
  end
737
762
  end
@@ -749,7 +774,7 @@ module Squared
749
774
  end
750
775
 
751
776
  def event(name, key, *args, override: false, **kwargs, &blk)
752
- data = @events[name.to_sym] ||= {}
777
+ data = @events[name.to_sym]
753
778
  items = if override
754
779
  data[key.to_sym] = []
755
780
  else
@@ -803,6 +828,8 @@ module Squared
803
828
  graph_set val
804
829
  when :pass
805
830
  pass_set val
831
+ when :only
832
+ only_set val
806
833
  when :exclude
807
834
  exclude_set val
808
835
  when :parent
@@ -963,11 +990,11 @@ module Squared
963
990
  puts_oe(*args, pipe: pipe)
964
991
  end
965
992
 
966
- def run(cmd = @session, var = nil, exception: @exception, sync: true, from: nil, banner: true, chdir: path,
993
+ def run(cmd = @session, var = nil, exception: self.exception, sync: true, from: nil, banner: true, chdir: path,
967
994
  interactive: nil, **)
968
995
  unless cmd
969
- from = from&.to_s || 'unknown'
970
- return warn log_message(Logger::WARN, 'no command given', subject: project, hint: from, pass: true)
996
+ warn log_message(Logger::WARN, 'no command given', subject: project, hint: from || 'unknown', pass: true)
997
+ return
971
998
  end
972
999
  i = interactive && !(@session && option('y'))
973
1000
  cmd = cmd.target if cmd.is_a?(OptionPartition)
@@ -981,9 +1008,7 @@ module Squared
981
1008
  else
982
1009
  ['Run', 'Y']
983
1010
  end
984
- unless confirm("#{title}? [#{sub_style(cmd, styles: theme[:inline])}]", y)
985
- raise_error('user cancelled', hint: from)
986
- end
1011
+ exit 1 unless confirm("#{title}? [#{sub_style(cmd, styles: theme[:inline])}]", y)
987
1012
  end
988
1013
  log&.info cmd
989
1014
  on :first, from
@@ -1007,10 +1032,7 @@ module Squared
1007
1032
  ret = shell(*args, chdir: chdir, exception: exception)
1008
1033
  end
1009
1034
  rescue StandardError => e
1010
- log&.error e
1011
- ret = on :error, from, e
1012
- raise unless ret == true
1013
-
1035
+ on_error(from, e, exception: true)
1014
1036
  false
1015
1037
  else
1016
1038
  on :last, from
@@ -1142,7 +1164,7 @@ module Squared
1142
1164
  done
1143
1165
  end
1144
1166
 
1145
- def graph_collect(target, start = [], data: {}, pass: [])
1167
+ def graph_collect(target, start = [], data: {}, pass: [], root: [])
1146
1168
  deps = []
1147
1169
  (start.empty? ? target.instance_variable_get(:@graph) : start)&.each do |val|
1148
1170
  next if pass.include?(val)
@@ -1155,10 +1177,12 @@ module Squared
1155
1177
  items = workspace.find(group: val, ref: val.to_sym)
1156
1178
  end
1157
1179
  items.each do |proj|
1158
- next if pass.include?(proj.name)
1180
+ next if pass.include?(name = proj.name)
1159
1181
 
1160
- graph_collect(proj, data: data, pass: pass) if proj.graph? && !data.key?(proj.name)
1161
- next if (objs = data.fetch(proj.name, [])).include?(target)
1182
+ if proj.graph? && !data.key?(name) && !root.include?(name)
1183
+ graph_collect(proj, data: data, pass: pass, root: root + [name, target.name])
1184
+ end
1185
+ next if (objs = data.fetch(name, [])).include?(target)
1162
1186
 
1163
1187
  deps << proj
1164
1188
  deps.concat(objs)
@@ -1264,6 +1288,10 @@ module Squared
1264
1288
  puts 'Success'
1265
1289
  end
1266
1290
 
1291
+ def print_error(err, loglevel: Logger::WARN, pass: false)
1292
+ warn log_message(loglevel, err, pass: pass) if warning?
1293
+ end
1294
+
1267
1295
  def print_item(*val)
1268
1296
  puts unless printfirst?
1269
1297
  printsucc
@@ -1306,7 +1334,7 @@ module Squared
1306
1334
  ret.join("\n")
1307
1335
  end
1308
1336
 
1309
- def print_status(*args, from: nil)
1337
+ def print_status(*args, from: nil, **kwargs)
1310
1338
  return if stdin?
1311
1339
 
1312
1340
  case from
@@ -1315,6 +1343,12 @@ module Squared
1315
1343
  out[1] = sub_style(out[1], pat: /^( +major )(\d+)(.+)$/, styles: theme[:major], index: 2)
1316
1344
  out[1] = sub_style(out[1], pat: /^(.+)(minor )(\d+)(.+)$/, styles: theme[:active], index: 3)
1317
1345
  puts out
1346
+ when :completed
1347
+ if verbose && kwargs[:start]
1348
+ msg = sub_style('completed', styles: theme[:active])
1349
+ puts log_message(Logger::INFO, *args, msg, subject: kwargs[:subject],
1350
+ hint: time_format(epochtime - kwargs[:start]))
1351
+ end
1318
1352
  end
1319
1353
  end
1320
1354
 
@@ -1599,13 +1633,9 @@ module Squared
1599
1633
  multiple: false, force: true, **kwargs)
1600
1634
  puts if !series && !printfirst?
1601
1635
  msg = "#{msg} (optional)" unless force
1602
- unless (ret = choice(msg, list, multiple: multiple, force: force, **kwargs)) || !force
1603
- raise_error 'user cancelled'
1604
- end
1605
- if ret.nil? || ret.empty?
1606
- return unless force
1607
-
1608
- exit 1
1636
+ unless (ret = choice(msg, list, multiple: multiple, force: force, **kwargs)) && !ret.empty?
1637
+ exit 1 if force
1638
+ return
1609
1639
  end
1610
1640
  ret = multiple ? ret.map! { |val| val.sub(trim, '') } : ret.sub(trim, '') if trim
1611
1641
  if column
@@ -1650,8 +1680,8 @@ module Squared
1650
1680
  ret
1651
1681
  end
1652
1682
 
1653
- def command_args(args, force: false, **kwargs)
1654
- return unless args.size == 1 && !option('i', 'interactive', **kwargs, equals: '0')
1683
+ def command_args(args, min: 0, force: false, **kwargs)
1684
+ return if args.size > min || option('i', 'interactive', **kwargs, equals: '0')
1655
1685
 
1656
1686
  readline('Enter arguments', force: force)
1657
1687
  end
@@ -1712,6 +1742,21 @@ module Squared
1712
1742
  val.scan(SEM_VER).first.yield_self { |data| fill ? semver(data) : data }
1713
1743
  end
1714
1744
 
1745
+ def semcmp(val, other)
1746
+ a, b = [val, other].map! { |ver| ver.match(SEM_VER) }
1747
+ return 1 unless a
1748
+ return -1 unless b
1749
+ return 0 if a[0] == b[0]
1750
+
1751
+ a, b = [a, b].map! { |c| [c[1], c[3], c[5] || '0'] }
1752
+ a.each_with_index do |c, index|
1753
+ next if c == (d = b[index])
1754
+
1755
+ return c.to_i < d.to_i ? 1 : -1
1756
+ end
1757
+ 0
1758
+ end
1759
+
1715
1760
  def indexitem(val)
1716
1761
  [$1.to_i, $2 && $2[1..-1]] if val =~ /\A[=^#{indexchar}](\d+)(:.+)?\z/
1717
1762
  end
@@ -1753,9 +1798,9 @@ module Squared
1753
1798
  end
1754
1799
 
1755
1800
  def on(event, from, *args, **kwargs)
1756
- return unless from && (data = @events[event])
1801
+ return unless from && @events.key?(event)
1757
1802
 
1758
- data[from]&.each do |obj|
1803
+ @events[event][from]&.each do |obj|
1759
1804
  target, opts = if obj.is_a?(Array) && obj[1].is_a?(Hash)
1760
1805
  [obj[0], kwargs.empty? ? obj[1] : obj[1].merge(kwargs)]
1761
1806
  else
@@ -1772,10 +1817,19 @@ module Squared
1772
1817
  end
1773
1818
  end
1774
1819
 
1820
+ def on_error(err, from, exception: self.exception, pass: false, dryrun: false)
1821
+ log&.error err
1822
+ unless dryrun
1823
+ ret = on :error, from, err
1824
+ raise err if exception && ret != true
1825
+ end
1826
+ print_error(err, pass: pass) unless ret
1827
+ end
1828
+
1775
1829
  def pwd_set(pass: false, from: nil)
1776
1830
  pass = semscan(pass).join <= RUBY_VERSION if pass.is_a?(String)
1777
1831
  pwd = Dir.pwd
1778
- if (path.to_s == pwd || pass == true) && !workspace.jruby_win?
1832
+ if (path.to_s == pwd || pass == true) && (workspace.mri? || !workspace.windows?)
1779
1833
  ret = yield
1780
1834
  else
1781
1835
  Dir.chdir(path)
@@ -1783,9 +1837,7 @@ module Squared
1783
1837
  Dir.chdir(pwd)
1784
1838
  end
1785
1839
  rescue StandardError => e
1786
- log&.error e
1787
- ret = on :error, from, e
1788
- raise if exception && ret != true
1840
+ on_error e, from
1789
1841
  else
1790
1842
  ret
1791
1843
  end
@@ -1860,25 +1912,6 @@ module Squared
1860
1912
  @parent = val if val.is_a?(Project::Base)
1861
1913
  end
1862
1914
 
1863
- def exception_set(val)
1864
- @exception = env_bool(val, workspace.exception, strict: true)
1865
- end
1866
-
1867
- def pipe_set(val)
1868
- @pipe = env_pipe(val, workspace.pipe, strict: true)
1869
- end
1870
-
1871
- def verbose_set(val)
1872
- @verbose = case val
1873
- when NilClass
1874
- workspace.verbose
1875
- when String
1876
- env_bool(val, workspace.verbose, strict: true, index: true)
1877
- else
1878
- val
1879
- end
1880
- end
1881
-
1882
1915
  def graph_set(val)
1883
1916
  @graph = if val
1884
1917
  Array(val).map { |s| workspace.prefix ? workspace.task_name(s).to_sym : s.to_sym }.freeze
@@ -1886,7 +1919,11 @@ module Squared
1886
1919
  end
1887
1920
 
1888
1921
  def pass_set(val)
1889
- @pass = (val ? as_a(val, :to_s) : []).freeze
1922
+ @pass = Array(val).freeze
1923
+ end
1924
+
1925
+ def only_set(val)
1926
+ @only = val && as_a(val, :to_s).freeze
1890
1927
  end
1891
1928
 
1892
1929
  def exclude_set(val)
@@ -1945,6 +1982,10 @@ module Squared
1945
1982
  end
1946
1983
  end
1947
1984
 
1985
+ def task_pass?(key)
1986
+ @only ? !@only.include?(key) : @pass.include?(key)
1987
+ end
1988
+
1948
1989
  def projectpath?(val)
1949
1990
  Pathname.new(val).cleanpath.yield_self do |file|
1950
1991
  file.absolute? ? file.to_s.start_with?(File.join(path, '')) : !file.to_s.start_with?(File.join('..', ''))
@@ -2046,6 +2087,14 @@ module Squared
2046
2087
  BLK_SET
2047
2088
  end
2048
2089
 
2090
+ def hashobj
2091
+ Workspace::Support.hashobj
2092
+ end
2093
+
2094
+ def hashlist
2095
+ Workspace::Support.hashlist
2096
+ end
2097
+
2049
2098
  def borderstyle
2050
2099
  workspace.banner_get(*@ref, group: group)&.border || theme[:border]
2051
2100
  end