squared 0.4.19 → 0.5.0

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,6 +9,7 @@ module Squared
9
9
  module Workspace
10
10
  module Project
11
11
  class Base
12
+ include Comparable
12
13
  include Common::Format
13
14
  include System
14
15
  include Shell
@@ -16,13 +17,12 @@ module Squared
16
17
  include Utils
17
18
  include Support
18
19
  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 only exclude].freeze
22
+ pass exclude].freeze
23
23
  BLK_SET = %i[run depend doc lint test copy clean].freeze
24
- SEM_VER = /\b(\d+)(?:(\.)(\d+))?(?:(\.)(\d+))?[-.]?(\S+)?\b/.freeze
25
- URI_SCHEME = %r{\A([a-z][a-z\d+-.]*)://[^@:\[\]\\^<>|\s]}i.freeze
24
+ SEM_VER = /\b(\d+)(?:(\.)(\d+))?(?:(\.)(\d+)(\S+)?)?\b/.freeze
25
+ URI_SCHEME = %r{^([a-z][a-z\d+-.]*)://[^@:\[\]\\^<>|\s]}i.freeze
26
26
  TASK_METADATA = Rake::TaskManager.record_task_metadata
27
27
  private_constant :VAR_SET, :BLK_SET, :SEM_VER, :URI_SCHEME, :TASK_METADATA
28
28
 
@@ -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, :group, :parent, :dependfile,
77
- :exception, :pipe, :verbose
76
+ attr_reader :name, :project, :workspace, :path, :theme, :exception, :pipe, :verbose,
77
+ :group, :parent, :dependfile
78
78
 
79
79
  def initialize(workspace, path, name, *, group: nil, first: {}, last: {}, error: {}, common: ARG[:COMMON],
80
80
  **kwargs)
@@ -89,24 +89,32 @@ module Squared
89
89
  @test = kwargs[:test]
90
90
  @copy = kwargs[:copy]
91
91
  @clean = kwargs[:clean]
92
+ @version = kwargs[:version]
92
93
  @release = kwargs[:release]
93
- self.version = kwargs[:version]
94
- self.exception = kwargs[:exception]
95
- self.pipe = kwargs[:pipe]
96
- self.verbose = kwargs[:verbose]
97
94
  @output = []
98
95
  @ref = []
99
96
  @children = []
100
- @events = hashobj.update({ first: first, last: last, error: error })
101
- @envname = env_key(@name).freeze
97
+ @events = {
98
+ first: first,
99
+ last: last,
100
+ error: error
101
+ }
102
+ @envname = @name.gsub(/[^\w]+/, '_').upcase.freeze
102
103
  @desc = (@name.include?(':') ? @name.split(':').join(ARG[:SPACE]) : @name).freeze
103
104
  @parent = nil
104
105
  @global = false
106
+ @log = nil
107
+ @dev = nil
108
+ @prod = nil
109
+ @withargs = nil
110
+ @session = nil
105
111
  @index = -1
106
112
  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]
107
116
  graph_set kwargs[:graph]
108
117
  pass_set kwargs[:pass]
109
- only_set kwargs[:only]
110
118
  exclude_set kwargs[:exclude]
111
119
  archive_set kwargs[:archive]
112
120
  theme_set common
@@ -168,7 +176,9 @@ module Squared
168
176
  def initialize_events(ref, **)
169
177
  return unless (events = @workspace.events_get(group: @group, ref: ref))
170
178
 
171
- events.each { |task, data| data.each { |ev, blk| @events[ev][task] ||= [blk] } }
179
+ events.each do |task, data|
180
+ data.each { |ev, blk| (@events[ev] ||= {})[task] ||= [blk] }
181
+ end
172
182
  end
173
183
 
174
184
  def initialize_logger(log: nil, **)
@@ -195,7 +205,7 @@ module Squared
195
205
  file &&= @workspace.home.join(env('LOG_DIR', ''), file).realdirpath
196
206
  rescue StandardError => e
197
207
  file = nil
198
- warn log_message(Logger::WARN, e) if warning?
208
+ warn log_message(Logger::WARN, e, pass: true) if warning?
199
209
  end
200
210
  log[:progname] ||= @name
201
211
  if (val = env('LOG_LEVEL', ignore: false))
@@ -208,7 +218,7 @@ module Squared
208
218
  def initialize_env(dev: nil, prod: nil, **)
209
219
  @dev = env_match('BUILD', dev, suffix: 'DEV', strict: true)
210
220
  @prod = env_match('BUILD', prod, suffix: 'PROD', strict: true)
211
- unless @output[2] == false || !(val = env('BUILD', suffix: 'ENV'))
221
+ if @output[2] != false && (val = env('BUILD', suffix: 'ENV'))
212
222
  @output[2] = parse_json(val, hint: "BUILD_#{@envname}_ENV") || @output[2]
213
223
  end
214
224
  unless @output[0] == false || @output[0].is_a?(Array)
@@ -233,26 +243,21 @@ module Squared
233
243
  end
234
244
  end
235
245
 
236
- def ==(other)
237
- equal?(other)
238
- end
239
-
240
246
  def <=>(other)
241
- return unless workspace == other.workspace
242
- return 0 if equal?(other)
247
+ return 0 unless workspace == other.workspace
243
248
 
244
249
  a, b = graph_deps
245
250
  return 1 if a.include?(other)
246
251
 
247
252
  c, d = graph_deps other
248
- e = b - d
249
- f = d - b
253
+ e = b.reject { |val| d.include?(val) }
254
+ f = d.reject { |val| b.include?(val) }
250
255
  if parent == other.parent
251
256
  g = []
252
257
  h = []
253
258
  else
254
- g = a - c
255
- h = c - a
259
+ g = a.reject { |val| c.include?(val) }
260
+ h = c.reject { |val| a.include?(val) }
256
261
  end
257
262
  g << self
258
263
  h << other
@@ -262,39 +267,18 @@ module Squared
262
267
  -1
263
268
  elsif h.any? { |val| e.include?(val) }
264
269
  1
265
- elsif e.any? { |val| f.include?(val) } # rubocop:disable Lint/DuplicateBranch
270
+ elsif e.any? { |val| f.include?(val) }
266
271
  -1
267
- elsif f.any? { |val| e.include?(val) } # rubocop:disable Lint/DuplicateBranch
272
+ elsif f.any? { |val| e.include?(val) }
268
273
  1
269
274
  elsif @index >= 0 && (i = other.instance_variable_get(:@index)) >= 0
270
- @index <=> i
275
+ @index <= i ? -1 : 1
276
+ else
277
+ 0
271
278
  end
272
279
  rescue StandardError => e
273
280
  log&.debug e
274
- nil
275
- end
276
-
277
- def version=(val)
278
- @version = val&.to_s
279
- end
280
-
281
- def exception=(val)
282
- @exception = env_bool(val, workspace.exception, strict: true)
283
- end
284
-
285
- def pipe=(val)
286
- @pipe = env_pipe(val, workspace.pipe, strict: true)
287
- end
288
-
289
- def verbose=(val)
290
- @verbose = case val
291
- when NilClass
292
- workspace.verbose
293
- when String
294
- env_bool(val, workspace.verbose, strict: true, index: true)
295
- else
296
- val
297
- end
281
+ 0
298
282
  end
299
283
 
300
284
  def ref
@@ -307,41 +291,41 @@ module Squared
307
291
 
308
292
  namespace name do
309
293
  Base.subtasks do |action, flags|
310
- next if task_pass?(action)
294
+ next if @pass.include?(action)
311
295
 
312
296
  namespace action do
313
297
  flags.each do |flag|
314
298
  case action
315
299
  when 'graph'
316
- break unless graph?
300
+ next unless graph?
317
301
 
318
302
  format_desc action, flag, '(-)project*'
319
303
  task flag do |_, args|
320
- args = args.to_a.reject { |val| name == val.to_s }
304
+ args = args.to_a.reject { |val| name == val }
321
305
  if flag == :run
322
306
  graph args
323
307
  else
324
308
  out, done = graph(args, out: [])
325
309
  out.map! do |val|
326
310
  done.each_with_index do |proj, i|
327
- next unless val.match?(/ #{Regexp.escape(proj.name)}(?:@\d|\z)/)
328
-
329
- val += " (#{i.succ})"
330
- break
311
+ if val.match?(/ #{Regexp.escape(proj.name)}(?:@\d|\z)/)
312
+ val += " (#{i.succ})"
313
+ break
314
+ end
331
315
  end
332
316
  val
333
317
  end
334
318
  emphasize(out, title: path, right: true, border: borderstyle, sub: [
335
319
  { pat: /\A(#{Regexp.escape(path.to_s)})(.*)\z/, styles: theme[:header] },
336
320
  { pat: /\A(#{Regexp.escape(name)})(.*)\z/, styles: theme[:active] },
337
- { pat: /\A(.+ )(\()(\d+)(\))(.*)\z/, styles: theme[:inline], index: 3 }
321
+ { pat: /\A((?~ \() \()(\d+)(\).*)\z/, styles: theme[:inline], index: 2 }
338
322
  ])
339
323
  end
340
324
  end
341
325
  when 'unpack'
342
326
  format_desc(action, flag, 'tag/url,dir,digest?,f|force?', before: flag == :ext ? 'ext' : nil)
343
327
  params = %i[tag dir digest force]
344
- params.unshift(:ext) if flag == :ext
328
+ params.prepend(:ext) if flag == :ext
345
329
  task flag, params do |_, args|
346
330
  ext = flag == :ext ? param_guard(action, flag, args: args, key: :ext) : flag.to_s
347
331
  tag = param_guard(action, flag, args: args, key: :tag)
@@ -396,17 +380,8 @@ module Squared
396
380
  return self
397
381
  elsif !projectpath?(path = basepath(path)) || !checkdir?(path)
398
382
  return self
399
- else
400
- name = case name
401
- when String, Symbol
402
- name.to_s
403
- end
404
- end
405
- if @withargs
406
- data = @withargs.dup
407
- data.merge!(kwargs)
408
- kwargs = data
409
383
  end
384
+ kwargs = @withargs.yield_self { |data| data.dup.update(kwargs) } if @withargs
410
385
  kwargs[:group] = group unless kwargs.key?(:group)
411
386
  kwargs[:ref] = ref unless kwargs.key?(:ref)
412
387
  parent = self
@@ -436,7 +411,7 @@ module Squared
436
411
 
437
412
  out = obj.link(self, *args, **kwargs, &blk) if obj.respond_to?(:link)
438
413
  if !out
439
- warn log_message(Logger::WARN, 'link not compatible', subject: obj.to_s, hint: name)
414
+ warn log_message(Logger::WARN, 'link not compatible', subject: obj.to_s, hint: name, pass: true)
440
415
  elsif out.respond_to?(:build)
441
416
  out.build
442
417
  end
@@ -455,13 +430,13 @@ module Squared
455
430
  if args.first.is_a?(Struct)
456
431
  f, blk = args.first.to_a
457
432
  args[0] = instance_eval(&blk) || f
458
- return unless args.first
433
+ return unless args[0]
459
434
  end
460
435
  if args.all? { |val| val.is_a?(Array) }
461
436
  cmd = []
462
437
  var = {}
463
438
  args.each do |val|
464
- next instance_exec(*val[1..-1], &val.first) if val.first.is_a?(Proc)
439
+ next instance_exec(*val[1..-1], &val[0]) if val.first.is_a?(Proc)
465
440
 
466
441
  a, b, c, d, e = val
467
442
  case b
@@ -478,7 +453,7 @@ module Squared
478
453
 
479
454
  cmd << a if (a = compose(as_get(b), d, script: true, args: e, from: from))
480
455
  end
481
- var.merge!(c) if c.is_a?(Hash)
456
+ var.update(c) if c.is_a?(Hash)
482
457
  end
483
458
  cmd = cmd.join(' && ')
484
459
  else
@@ -491,9 +466,9 @@ module Squared
491
466
  case opts
492
467
  when Hash
493
468
  opts = append_hash(opts, build: true)
494
- cmd = Array(cmd).push(flags).concat(opts).compact.join(' ')
469
+ cmd = as_a(cmd).append(flags).concat(opts).compact.join(' ')
495
470
  when Enumerable
496
- cmd = Array(cmd).concat(opts.to_a)
471
+ cmd = as_a(cmd).concat(opts.to_a)
497
472
  cmd.map! { |val| "#{val} #{flags}" } if flags
498
473
  cmd = cmd.join(' && ')
499
474
  else
@@ -522,12 +497,16 @@ module Squared
522
497
  if proj.respond_to?(meth.to_sym)
523
498
  begin
524
499
  proj.__send__(meth, sync: sync)
525
- next
526
500
  rescue StandardError => e
527
- on_error(:prereqs, e, exception: true)
501
+ ret = on(:error, :prereqs, e)
502
+ raise unless ret == true
503
+ else
504
+ next
528
505
  end
529
506
  end
530
- warn log_message(Logger::WARN, name, 'method not found', subject: 'prereqs', hint: meth)
507
+ if warning?
508
+ warn log_message(Logger::WARN, name, 'method not found', subject: 'prereqs', hint: meth, pass: true)
509
+ end
531
510
  end
532
511
  elsif proj.build?
533
512
  proj.build(sync: sync)
@@ -577,7 +556,9 @@ module Squared
577
556
  begin
578
557
  @clean.each { |cmd, opts| build(cmd.to_s, opts, sync: sync) }
579
558
  rescue StandardError => e
580
- on_error e, from
559
+ log&.error e
560
+ ret = on(:error, from, e)
561
+ raise if exception && ret != true
581
562
  end
582
563
  else
583
564
  if @clean.is_a?(Enumerable) && !series?(@clean)
@@ -626,7 +607,8 @@ module Squared
626
607
  end
627
608
  ret = graph_branch(self, data, tasks, out, sync: sync, pass: pass)
628
609
  rescue StandardError => e
629
- on_error(:graph, e, exception: true)
610
+ ret = on(:error, :graph, e)
611
+ raise unless ret == true
630
612
  else
631
613
  if out
632
614
  [out, ret]
@@ -635,13 +617,13 @@ module Squared
635
617
  end
636
618
  end
637
619
 
638
- def unpack(target, file = nil, uri: nil, sync: true, digest: nil, ext: nil, force: false, depth: 1, headers: {},
639
- verbose: self.verbose, from: :unpack)
620
+ def unpack(target, uri:, sync: true, digest: nil, ext: nil, force: false, depth: 1, headers: {}, from: :unpack)
621
+ require 'open-uri'
640
622
  if !target.exist?
641
623
  target.mkpath
642
624
  elsif !target.directory?
643
625
  raise_error('invalid location', hint: target)
644
- elsif !file && !target.empty?
626
+ elsif !target.empty?
645
627
  raise_error('directory not empty', hint: target) unless force || env('UNPACK_FORCE')
646
628
  create = true
647
629
  end
@@ -662,66 +644,58 @@ module Squared
662
644
  when 128, 'sha512'
663
645
  Digest::SHA512
664
646
  else
665
- raise_error "invalid checksum: #{digest}"
647
+ raise_error("invalid checksum: #{digest}", hint: name)
666
648
  end
667
649
  end
668
650
  if (val = env('HEADERS')) && (val = parse_json(val, hint: "HEADERS_#{@envname}"))
669
651
  headers = headers.is_a?(Hash) ? headers.merge(val) : val
670
652
  end
671
- if file
672
- ext ||= File.extname(file)[1..-1]
673
- else
674
- data = nil
675
- (uri = Array(uri)).each_with_index do |url, index|
676
- fetch_uri(url, headers) do |f|
677
- data = f.read
678
- if algo && algo.hexdigest(data) != digest
679
- data = nil
680
- raise_error("checksum failed: #{digest}", hint: url) if index == uri.size - 1
681
- end
682
- next if ext && index == 0
683
-
684
- case f.content_type
685
- when 'application/zip'
686
- ext = 'zip'
687
- when 'application/x-gzip'
688
- ext = 'tgz'
689
- when 'application/x-xz'
690
- ext = 'txz'
691
- end
653
+ data = nil
654
+ (uri = as_a(uri)).each_with_index do |url, index|
655
+ URI.open(url, headers) do |f|
656
+ data = f.read
657
+ if algo && algo.hexdigest(data) != digest
658
+ data = nil
659
+ raise_error("checksum failed: #{digest}", hint: url) if index == uri.size - 1
660
+ end
661
+ next if ext && index == 0
662
+
663
+ case f.content_type
664
+ when 'application/zip'
665
+ ext = 'zip'
666
+ when 'application/x-gzip'
667
+ ext = 'tgz'
668
+ when 'application/x-xz'
669
+ ext = 'txz'
692
670
  end
693
- break uri = url if data
694
- end
695
- unless data && (ext ||= URI.parse(uri).path[/\.(\w+)(?:\?|\z)/, 1])
696
- raise_error("no content#{data ? ' type' : ''}", hint: uri)
697
671
  end
672
+ break uri = url if data
673
+ end
674
+ unless data && (ext ||= URI.parse(uri).path[/\.(\w+)(?:\?|\z)/, 1])
675
+ raise_error("no content#{data ? ' type' : ''}", hint: uri)
698
676
  end
699
677
  ext = ext.downcase
700
678
  if (val = env("#{%w[zip 7z gem].include?(ext) ? ext.upcase : 'TAR'}_DEPTH", ignore: false))
701
679
  depth = val.to_i
702
680
  end
703
681
  begin
704
- unless file
705
- if ext == 'gem'
706
- dir = Dir.mktmpdir
707
- file = File.new(File.join(dir, File.basename(uri)), 'w')
708
- else
709
- require 'tempfile'
710
- file = Tempfile.new("#{name}-")
711
- end
712
- file.write(data)
713
- file.close
714
- file = Pathname.new(file)
715
- delete = true
682
+ if ext == 'gem'
683
+ dir = Dir.mktmpdir
684
+ file = File.new(File.join(dir, File.basename(uri)), 'w')
685
+ else
686
+ require 'tempfile'
687
+ file = Tempfile.new("#{name}-")
716
688
  end
689
+ file.write(data)
690
+ file.close
717
691
  if create
718
- warn log_message(Logger::WARN, 'force remove', subject: name, hint: target)
692
+ warn log_message(Logger::WARN, 'force remove', subject: name, hint: target, pass: true)
719
693
  target.rmtree
720
694
  target.mkpath
721
695
  end
722
696
  case ext
723
697
  when 'zip', 'aar'
724
- session 'unzip', shell_quote(file), quote_option('d', target)
698
+ session 'unzip', shell_quote(file.path), quote_option('d', target)
725
699
  when 'tar', 'tgz', 'tar.gz', 'tar.xz', 'gz', 'xz'
726
700
  flags = +(verbose ? 'v' : '')
727
701
  if ext.end_with?('gz')
@@ -729,28 +703,28 @@ module Squared
729
703
  elsif ext.end_with?('xz')
730
704
  flags += 'J'
731
705
  end
732
- session 'tar', "-x#{flags}", basic_option('strip-components', depth), quote_option('f', file),
706
+ session 'tar', "-x#{flags}", basic_option('strip-components', depth), quote_option('f', file.path),
733
707
  quote_option('C', target)
734
708
  depth = 0
735
709
  when '7z'
736
- session '7z', 'x', shell_quote(file), "-o#{shell_quote(target)}"
710
+ session '7z', 'x', shell_quote(file.path), "-o#{shell_quote(target)}"
737
711
  when 'gem'
738
- session 'gem', 'unpack', shell_quote(file), quote_option('target', target)
712
+ session 'gem', 'unpack', shell_quote(file.path), quote_option('target', target)
739
713
  depth = 0 unless val
740
714
  else
741
- raise_error("unsupported format: #{ext}", hint: uri || file)
715
+ raise_error("unsupported format: #{ext}", hint: uri)
742
716
  end
743
- run(sync: sync, banner: verbose, from: from)
717
+ run(sync: sync, from: from)
744
718
  while depth > 0 && target.children.size == 1
745
719
  entry = target.children.first
746
720
  break unless entry.directory?
747
721
 
748
722
  i = 0
749
- while (dest = target + "#{File.basename(file)}-#{i}").exist?
723
+ while (dest = target + "#{File.basename(file.path)}-#{i}").exist?
750
724
  i += 1
751
725
  end
752
726
  FileUtils.mv(entry, dest)
753
- dest.children.each { |child| FileUtils.mv(child, target) }
727
+ dest.each_child { |child| FileUtils.mv(child, target) }
754
728
  dest.rmdir
755
729
  target = entry
756
730
  depth -= 1
@@ -758,8 +732,8 @@ module Squared
758
732
  ensure
759
733
  if dir
760
734
  remove_entry dir
761
- elsif delete && file&.exist?
762
- file.unlink
735
+ else
736
+ file&.unlink
763
737
  end
764
738
  end
765
739
  end
@@ -777,7 +751,7 @@ module Squared
777
751
  end
778
752
 
779
753
  def event(name, key, *args, override: false, **kwargs, &blk)
780
- data = @events[name.to_sym]
754
+ data = @events[name.to_sym] ||= {}
781
755
  items = if override
782
756
  data[key.to_sym] = []
783
757
  else
@@ -808,6 +782,13 @@ module Squared
808
782
  end
809
783
 
810
784
  def variable_set(key, *args, **kwargs, &blk)
785
+ if block_given?
786
+ if blocks.include?(key)
787
+ series key, &blk
788
+ return self
789
+ end
790
+ args = block_args args, &blk
791
+ end
811
792
  if variables.include?(key) || blocks.include?(key)
812
793
  val = case args.size
813
794
  when 0
@@ -824,14 +805,10 @@ module Squared
824
805
  graph_set val
825
806
  when :pass
826
807
  pass_set val
827
- when :only
828
- only_set val
829
808
  when :exclude
830
809
  exclude_set val
831
810
  when :parent
832
811
  parent_set val
833
- when :archive
834
- archive_set val
835
812
  when :run
836
813
  run_set(*args, **kwargs)
837
814
  when :script
@@ -841,14 +818,7 @@ module Squared
841
818
  when :dependfile
842
819
  @dependfile = basepath(*args)
843
820
  else
844
- if block_given?
845
- if blocks.include?(key)
846
- series key, &blk
847
- return self
848
- end
849
- val = block_args val, &blk
850
- end
851
- instance_variable_set(:"@#{key}", val.first)
821
+ instance_variable_set(:"@#{key}", val)
852
822
  end
853
823
  else
854
824
  log&.warn "variable_set: @#{key} (private)"
@@ -948,7 +918,7 @@ module Squared
948
918
  def log
949
919
  return @log unless @log.is_a?(Array)
950
920
 
951
- @log = Logger.new(enabled? ? @log.first : nil, **@log.last)
921
+ @log = Logger.new(enabled? ? @log[0] : nil, **@log[1])
952
922
  end
953
923
 
954
924
  def allref
@@ -989,38 +959,28 @@ module Squared
989
959
 
990
960
  private
991
961
 
992
- def puts(*args, **kwargs)
993
- log_console(*args, pipe: kwargs[:pipe] || pipe)
962
+ def puts(*args)
963
+ puts_oe(*args, pipe: pipe)
994
964
  end
995
965
 
996
- def run(cmd = @session, var = nil, exception: self.exception, sync: true, from: nil, banner: true, chdir: path,
997
- interactive: nil, hint: nil, **)
966
+ def run(cmd = @session, var = nil, exception: @exception, sync: true, from: nil, banner: true, chdir: path, **)
998
967
  unless cmd
999
- warn log_message(Logger::WARN, 'no command given', subject: project, hint: from || 'unknown', pass: true)
968
+ if warning?
969
+ from &&= from.to_s
970
+ warn log_message(Logger::WARN, from || 'unknown', subject: project, hint: 'no command given', pass: true)
971
+ end
1000
972
  return
1001
973
  end
1002
974
  cmd = cmd.target if cmd.is_a?(OptionPartition)
1003
- if interactive && (!@session || !option('y'))
1004
- title, y = case interactive
1005
- when Array
1006
- interactive
1007
- when String
1008
- [interactive, 'N']
1009
- else
1010
- ['Run', 'Y']
1011
- end
1012
- yn = y == 'Y' ? 'Y/n' : 'y/N'
1013
- exit 1 unless confirm("#{title}? [#{sub_style(cmd.to_s, styles: theme[:inline])}] [#{yn}] ", y)
1014
- end
1015
975
  cmd = session_done cmd
1016
976
  log&.info cmd
1017
977
  on :first, from
1018
978
  begin
1019
- if cmd.match?(/\A[^:]+:[^:]/) && workspace.task_defined?(cmd)
979
+ if cmd.start_with?(/[^:]+:[^:]/) && workspace.task_defined?(cmd)
1020
980
  log&.warn "ENV discarded: #{var}" if var
1021
981
  task_invoke(cmd, exception: exception, warning: warning?)
1022
982
  else
1023
- print_item format_banner(hint ? "#{cmd} (#{hint})" : cmd, banner: banner) if sync
983
+ print_item format_banner(cmd, banner: banner) if sync
1024
984
  if var != false && (pre = runenv)
1025
985
  case pre
1026
986
  when Hash
@@ -1028,14 +988,17 @@ module Squared
1028
988
  when Enumerable
1029
989
  cmd = command(*pre.to_a, cmd)
1030
990
  else
1031
- cmd = command(pre, cmd)
991
+ cmd = command pre, cmd
1032
992
  end
1033
993
  end
1034
994
  args = var.is_a?(Hash) ? [var, cmd] : [cmd]
1035
995
  ret = shell(*args, chdir: chdir, exception: exception)
1036
996
  end
1037
997
  rescue StandardError => e
1038
- on_error(from, e, exception: true)
998
+ log&.error e
999
+ ret = on(:error, from, e)
1000
+ raise unless ret == true
1001
+
1039
1002
  false
1040
1003
  else
1041
1004
  on :last, from
@@ -1048,7 +1011,7 @@ module Squared
1048
1011
  begin
1049
1012
  cmd.flatten.each { |val| run(val, env, sync: sync, banner: banner, **kwargs) }
1050
1013
  rescue StandardError => e
1051
- ret = on :error, from, e
1014
+ ret = on(:error, from, e)
1052
1015
  raise unless ret == true
1053
1016
  end
1054
1017
  on :last, from
@@ -1070,7 +1033,7 @@ module Squared
1070
1033
  elsif obj.is_a?(Array) && obj.any? { |val| !val.is_a?(String) }
1071
1034
  build(*obj, **kwargs)
1072
1035
  elsif obj
1073
- run_s(*Array(obj), **kwargs)
1036
+ run_s(obj.is_a?(Enumerable) ? obj.to_a : obj, **kwargs)
1074
1037
  end
1075
1038
  end
1076
1039
  end
@@ -1117,7 +1080,7 @@ module Squared
1117
1080
 
1118
1081
  t = dedupe.call(proj.name)
1119
1082
  j = if out
1120
- if i == items.size - 1 || check.call(post = items[(i + 1)..-1]).empty?
1083
+ if i == items.size - 1 || check.call(post = items[i + 1..-1]).empty?
1121
1084
  true
1122
1085
  elsif !t.empty? && depth > 0
1123
1086
  post.reject { |pr| t.include?(pr) }.empty?
@@ -1129,9 +1092,9 @@ module Squared
1129
1092
  end
1130
1093
  if !out
1131
1094
  if !tasks && (script = workspace.script_get(:graph, group: proj.group, ref: proj.allref))
1132
- tasks = script[:graph]
1095
+ group = script[:graph]
1133
1096
  end
1134
- (tasks || (dev? ? ['build', 'copy'] : ['depend', 'build'])).each do |meth|
1097
+ (tasks || group || (dev? ? ['build', 'copy'] : ['depend', 'build'])).each do |meth|
1135
1098
  next if pass.include?(meth)
1136
1099
 
1137
1100
  if workspace.task_defined?(cmd = task_join(proj.name, meth))
@@ -1142,7 +1105,7 @@ module Squared
1142
1105
  end
1143
1106
  run(cmd, sync: false, banner: false)
1144
1107
  ENV.delete(key) if key
1145
- elsif proj.has?(meth, tasks ? nil : workspace.baseref)
1108
+ elsif proj.has?(meth, tasks || group ? nil : workspace.baseref)
1146
1109
  proj.__send__(meth.to_sym, sync: sync)
1147
1110
  end
1148
1111
  end
@@ -1167,7 +1130,7 @@ module Squared
1167
1130
  done
1168
1131
  end
1169
1132
 
1170
- def graph_collect(target, start = [], data: {}, pass: [], root: [])
1133
+ def graph_collect(target, start = [], data: {}, pass: [])
1171
1134
  deps = []
1172
1135
  (start.empty? ? target.instance_variable_get(:@graph) : start)&.each do |val|
1173
1136
  next if pass.include?(val)
@@ -1179,13 +1142,12 @@ module Squared
1179
1142
  else
1180
1143
  items = workspace.find(group: val, ref: val.to_sym)
1181
1144
  end
1145
+
1182
1146
  items.each do |proj|
1183
- next if pass.include?(name = proj.name)
1147
+ next if pass.include?(proj.name)
1184
1148
 
1185
- if proj.graph? && !data.key?(name) && !root.include?(name)
1186
- graph_collect(proj, data: data, pass: pass, root: root + [name, target.name])
1187
- end
1188
- next if (objs = data.fetch(name, [])).include?(target)
1149
+ graph_collect(proj, data: data, pass: pass) if proj.graph? && !data.key?(proj.name)
1150
+ next if (objs = data.fetch(proj.name, [])).include?(target)
1189
1151
 
1190
1152
  deps << proj
1191
1153
  deps.concat(objs)
@@ -1225,16 +1187,16 @@ module Squared
1225
1187
  end
1226
1188
  return ret == equals.to_s unless equals.nil?
1227
1189
 
1228
- ret.empty? || (ignore && Array(ignore).any? { |val| ret == val.to_s }) ? default : ret
1190
+ ret.empty? || (ignore && as_a(ignore).any? { |val| ret == val.to_s }) ? default : ret
1229
1191
  end
1230
1192
 
1231
1193
  def session(*cmd, prefix: cmd.first, main: true, path: true, options: true)
1232
- prefix = stripext prefix.to_s
1233
- if path && (val = shell_bin(prefix))
1194
+ prefix = stripext(prefix.to_s).upcase
1195
+ if path && (val = ENV["PATH_#{prefix}"] || PATH[prefix] || PATH[prefix.to_sym])
1234
1196
  cmd[0] = shell_quote(val, force: false)
1235
1197
  end
1236
1198
  ret = JoinSet.new(cmd.flatten(1))
1237
- if options && (val = env("#{prefix.upcase}_OPTIONS"))
1199
+ if options && (val = env("#{prefix}_OPTIONS"))
1238
1200
  split_escape(val).each { |opt| ret.last(fill_option(opt), /\A(--?[^ =]+)[ =].+\z/m) }
1239
1201
  end
1240
1202
  main ? @session = ret : ret
@@ -1259,7 +1221,7 @@ module Squared
1259
1221
  def session_done(cmd)
1260
1222
  return cmd unless cmd.respond_to?(:done)
1261
1223
 
1262
- raise_error('no args added', hint: cmd.first) unless cmd.size > 1
1224
+ raise_error('no args added', hint: cmd.first || name) unless cmd.size > 1
1263
1225
  @session = nil if cmd == @session
1264
1226
  cmd.done
1265
1227
  end
@@ -1273,18 +1235,15 @@ module Squared
1273
1235
  def option(*args, target: @session, prefix: target&.first, **kwargs)
1274
1236
  if prefix
1275
1237
  args.each do |val|
1276
- ret = env(env_key(stripext(prefix), val), **kwargs)
1277
- return ret if ret
1238
+ next unless (ret = env("#{stripext(prefix)}_#{val.gsub(/\W/, '_')}".upcase, **kwargs))
1239
+ return ret unless block_given?
1240
+
1241
+ return yield ret
1278
1242
  end
1279
1243
  end
1280
1244
  nil
1281
1245
  end
1282
1246
 
1283
- def option_sanitize(opts, list, target: @session, **kwargs)
1284
- op = OptionPartition.new(opts, list, target, project: self, **kwargs)
1285
- [op.extras, op.values]
1286
- end
1287
-
1288
1247
  def option_clear(opts, target: @session, **kwargs)
1289
1248
  return unless target
1290
1249
 
@@ -1295,10 +1254,6 @@ module Squared
1295
1254
  puts 'Success'
1296
1255
  end
1297
1256
 
1298
- def print_error(err, loglevel: Logger::WARN, pass: false)
1299
- warn log_message(loglevel, err, pass: pass) if warning?
1300
- end
1301
-
1302
1257
  def print_item(*val)
1303
1258
  puts unless printfirst?
1304
1259
  printsucc
@@ -1314,7 +1269,7 @@ module Squared
1314
1269
  styles = [:bold] + styles
1315
1270
  end
1316
1271
  end
1317
- n = Project.max_width(lines)
1272
+ n = line_width lines
1318
1273
  ch = ' ' * pad
1319
1274
  index = -1
1320
1275
  lines.map! do |val|
@@ -1330,7 +1285,7 @@ module Squared
1330
1285
  end
1331
1286
 
1332
1287
  def print_footer(*lines, sub: nil, reverse: false, right: false, **kwargs)
1333
- n = Project.max_width(lines)
1288
+ n = line_width lines
1334
1289
  lines.map! do |val|
1335
1290
  s = right ? val.rjust(n) : val.ljust(n)
1336
1291
  sub&.each { |h| s = sub_style(s, **h) }
@@ -1341,52 +1296,33 @@ module Squared
1341
1296
  ret.join("\n")
1342
1297
  end
1343
1298
 
1344
- def print_status(*args, from: nil, **kwargs)
1345
- return if stdin?
1346
-
1347
- case from
1348
- when :outdated
1349
- out = print_footer("major #{args[0]} / minor #{args[1]} / patch #{args[2]}", right: true).split("\n")
1350
- out[1] = sub_style(out[1], pat: /^( +major )(\d+)(.+)$/, styles: theme[:major], index: 2)
1351
- out[1] = sub_style(out[1], pat: /^(.+)(minor )(\d+)(.+)$/, styles: theme[:active], index: 3)
1352
- puts out
1353
- when :completed
1354
- if verbose && kwargs[:start]
1355
- msg = sub_style('completed', styles: theme[:active])
1356
- puts log_message(Logger::INFO, *args, msg, subject: kwargs[:subject],
1357
- hint: time_format(epochtime - kwargs[:start]))
1358
- end
1359
- end
1360
- end
1361
-
1362
1299
  def format_desc(action, flag, opts = nil, **kwargs)
1363
1300
  return unless TASK_METADATA
1364
1301
 
1365
- ret = [@desc, action]
1366
- ret << flag if flag
1367
- workspace.format_desc(ret, opts, **kwargs)
1302
+ workspace.format_desc([@desc, action, flag].compact, opts, **kwargs)
1368
1303
  end
1369
1304
 
1370
1305
  def format_banner(cmd, banner: true)
1371
1306
  return unless banner && banner?
1372
1307
 
1373
1308
  if (data = workspace.banner_get(*@ref, group: group))
1374
- return if data.empty?
1309
+ return if !data.command && data.order.empty?
1375
1310
 
1376
1311
  client = true
1377
1312
  else
1378
- data = { command: true, order: [:path], styles: theme[:banner], border: theme[:border] }
1313
+ data = Workspace::Support::BannerData.new(true, [:path], theme[:banner], theme[:border])
1379
1314
  end
1380
1315
  if verbose
1381
1316
  out = []
1382
- if data[:command]
1317
+ if data.command
1383
1318
  if cmd =~ /\A(?:"((?:[^"]|(?<=\\)")+)"|'((?:[^']|(?<=\\)')+)'|(\S+))( |\z)/
1384
1319
  path = $3 || $2 || $1
1385
- cmd = cmd.sub(path, stripext(path).upcase)
1320
+ name = stripext path
1321
+ cmd = cmd.sub(path, data.command == 0 ? name : name.upcase)
1386
1322
  end
1387
1323
  out << cmd
1388
1324
  end
1389
- data[:order].each do |val|
1325
+ data.order.each do |val|
1390
1326
  if val.is_a?(Array)
1391
1327
  s = ' '
1392
1328
  found = false
@@ -1396,7 +1332,7 @@ module Squared
1396
1332
  meth
1397
1333
  elsif respond_to?(meth)
1398
1334
  found = true
1399
- __send__(meth)
1335
+ __send__ meth
1400
1336
  end
1401
1337
  end
1402
1338
  val = val.compact.join(s)
@@ -1406,9 +1342,9 @@ module Squared
1406
1342
  end
1407
1343
  out << val.to_s
1408
1344
  end
1409
- print_banner(*out, styles: data[:styles], border: data[:border], client: client)
1345
+ print_banner(*out, styles: data.styles, border: data.border, client: client)
1410
1346
  elsif workspace.series.multiple?
1411
- "## #{__send__(data[:order].first || :path)} ##"
1347
+ "## #{__send__(data.order.first || :path)} ##"
1412
1348
  end
1413
1349
  end
1414
1350
 
@@ -1418,9 +1354,9 @@ module Squared
1418
1354
  unless items.empty?
1419
1355
  pad = items.size.to_s.size
1420
1356
  items.each_with_index do |val, i|
1421
- next unless matchany?(val.first, reg)
1357
+ next unless reg.empty? || reg.any? { |pat| val[0].match?(pat) }
1422
1358
 
1423
- out << "#{i.succ.to_s.rjust(pad)}. #{each ? each.call(val) : val.first}"
1359
+ out << "#{i.succ.to_s.rjust(pad)}. #{each ? each.call(val) : val[0]}"
1424
1360
  end
1425
1361
  end
1426
1362
  sub = [headerstyle]
@@ -1432,7 +1368,7 @@ module Squared
1432
1368
  out << ''
1433
1369
  end
1434
1370
  if from
1435
- out << (from = from.to_s)
1371
+ out << from
1436
1372
  pat = /\A(#{Regexp.escape(from)})(.*)\z/
1437
1373
  end
1438
1374
  else
@@ -1485,14 +1421,15 @@ module Squared
1485
1421
  end
1486
1422
 
1487
1423
  def append_any(val, target: @session, build: false, delim: false)
1424
+ return unless val
1425
+
1488
1426
  if delim && !target.include?('--')
1489
1427
  target << '--'
1490
1428
  else
1491
1429
  delim = false
1492
1430
  end
1431
+ val = shell_split(val) if val.is_a?(String)
1493
1432
  case val
1494
- when String
1495
- target << val
1496
1433
  when Hash
1497
1434
  append_hash(val, target: target, build: build)
1498
1435
  when Enumerable
@@ -1523,7 +1460,7 @@ module Squared
1523
1460
  return target << (if flag
1524
1461
  shell_option(opt, equals ? val : nil, quote: quote, escape: escape, force: force)
1525
1462
  else
1526
- shell_quote(val)
1463
+ shell_quote val
1527
1464
  end)
1528
1465
  end
1529
1466
  nil
@@ -1533,17 +1470,18 @@ module Squared
1533
1470
  **kwargs)
1534
1471
  return if list.empty?
1535
1472
 
1536
- ret = []
1537
- list.flatten.each do |flag|
1538
- next unless (val = option(flag, target: target, **kwargs))
1473
+ [].tap do |ret|
1474
+ list.flatten.each do |flag|
1475
+ next unless (val = option(flag, target: target, **kwargs))
1539
1476
 
1540
- if val == '0' && no
1541
- flag = "no-#{flag}"
1542
- val = nil
1477
+ if val == '0' && no
1478
+ flag = "no-#{flag}"
1479
+ val = nil
1480
+ end
1481
+ ret << shell_option(flag, equals ? val : nil, escape: escape, quote: quote, force: force)
1543
1482
  end
1544
- ret << shell_option(flag, equals ? val : nil, escape: escape, quote: quote, force: force)
1483
+ ret.each { |val| target << val } unless ret.empty?
1545
1484
  end
1546
- ret.each { |val| target << val } unless ret.empty?
1547
1485
  end
1548
1486
 
1549
1487
  def append_nocolor(target: @session)
@@ -1591,9 +1529,9 @@ module Squared
1591
1529
  end
1592
1530
 
1593
1531
  def collect_hash(data, pass: [])
1594
- ret = []
1595
- data.each { |key, val| ret.concat(val) unless pass.include?(key) }
1596
- ret
1532
+ [].tap do |ret|
1533
+ data.each { |key, val| ret.concat(val) unless pass.include?(key) }
1534
+ end
1597
1535
  end
1598
1536
 
1599
1537
  def parse_json(val, kind: Hash, hint: nil)
@@ -1601,20 +1539,11 @@ module Squared
1601
1539
  raise_error("invalid JSON #{kind.name}", val, hint: hint) if kind && !ret.is_a?(kind)
1602
1540
  rescue StandardError => e
1603
1541
  log&.warn e
1604
- warn log_message(Logger::WARN, e, subject: name) if warning?
1542
+ warn log_message(Logger::WARN, e, subject: name, pass: true) if warning?
1605
1543
  else
1606
1544
  ret
1607
1545
  end
1608
1546
 
1609
- def fetch_uri(*args, **kwargs, &blk)
1610
- require 'open-uri'
1611
- if RUBY_VERSION < '2.5'
1612
- open(*args, **kwargs, &blk)
1613
- else
1614
- URI.open(*args, **kwargs, &blk)
1615
- end
1616
- end
1617
-
1618
1547
  def param_guard(action, flag, args:, key: nil, pat: nil, values: nil)
1619
1548
  if args && key
1620
1549
  val = args.fetch(key, nil)
@@ -1629,7 +1558,7 @@ module Squared
1629
1558
  args
1630
1559
  end
1631
1560
 
1632
- def confirm_outdated(pkg, ver, rev, lock: false)
1561
+ def confirm_outdated(pkg, ver, rev, cur = nil, lock: false, col1: 0)
1633
1562
  a = sub_style(case rev
1634
1563
  when 1
1635
1564
  'MAJOR'
@@ -1637,45 +1566,46 @@ module Squared
1637
1566
  'MINOR'
1638
1567
  else
1639
1568
  'PATCH'
1640
- end, styles: theme[:header])
1641
- b = sub_style("#{pkg} #{ver}", styles: theme[:inline])
1569
+ end, styles: (rev == 1 && theme[:major]) || theme[:header])
1570
+ b = sub_style(pkg.ljust(col1), styles: theme[:inline])
1642
1571
  c, d = rev == 1 || lock ? ['y/N', 'N'] : ['Y/n', 'Y']
1643
- e = lock ? " #{sub_style('(locked)', styles: color(:red))}" : ''
1644
- confirm "Upgrade to #{a}? #{b + e} [#{c}] ", d
1572
+ e = lock ? sub_style((cur || 'locked').rjust(7), styles: color(:red)) : cur&.rjust(7)
1573
+ confirm "#{a}: #{b}#{e} #{sub_style(ver.rjust(col1 > 0 ? 10 : 0), styles: theme[:inline])} [#{c}] ", d
1645
1574
  end
1646
1575
 
1647
1576
  def choice_index(msg, list, values: nil, accept: nil, series: false, trim: nil, column: nil,
1648
1577
  multiple: false, force: true, **kwargs)
1649
1578
  puts if !series && !printfirst?
1650
1579
  msg = "#{msg} (optional)" unless force
1651
- unless (ret = choice(msg, list, multiple: multiple, force: force, **kwargs)) && !ret.empty?
1652
- exit 1 if force
1653
- return
1580
+ unless (ret = choice(msg, list, multiple: multiple, force: force, **kwargs)) || !force
1581
+ raise_error 'user cancelled'
1582
+ end
1583
+ if ret.nil? || ret.empty?
1584
+ return unless force
1585
+
1586
+ exit 1
1654
1587
  end
1655
1588
  ret = multiple ? ret.map! { |val| val.sub(trim, '') } : ret.sub(trim, '') if trim
1656
1589
  if column
1657
- a, b = Array(column)
1658
- ret = Array(ret).map! { |val| val[a, b || 1] }
1590
+ a, b = as_a column
1591
+ ret = as_a(ret).map! { |val| val[a, b || 1] }
1659
1592
  ret = ret.first unless multiple
1660
1593
  end
1661
1594
  if accept
1662
- hint = Array(ret).map { |val| sub_style(val, styles: theme[:inline]) }.join(', ')
1663
- accept = Array(accept).map { |val| Array(val) }
1595
+ a = as_a(ret).map { |val| sub_style(val, styles: theme[:inline]) }.join(', ')
1596
+ accept = as_a(accept).map { |val| as_a(val) }
1664
1597
  if accept.any? { |val| val[1] == true }
1665
1598
  ret = [ret]
1666
1599
  multiple = -1
1667
1600
  end
1668
1601
  loop do
1669
- item = accept.first
1670
- d, e = item[2] ? ['Y', '[Y/n]'] : ['N', '[y/N]']
1671
- c = confirm("#{item[0]}#{a ? " [#{a}]" : ''} #{e} ", d, timeout: 60)
1672
- if item[1] == true
1602
+ c = confirm("#{accept.first[0]}#{a ? " [#{a}]" : ''} [y/N] ", 'N', timeout: 60)
1603
+ if accept.shift[1] == true
1673
1604
  ret << c
1674
1605
  elsif !c
1675
1606
  break
1676
1607
  end
1677
- hint = nil
1678
- accept.shift
1608
+ a = nil
1679
1609
  break if accept.empty?
1680
1610
  end
1681
1611
  exit 1 unless accept.empty?
@@ -1696,8 +1626,8 @@ module Squared
1696
1626
  ret
1697
1627
  end
1698
1628
 
1699
- def command_args(args, min: 0, force: false, **kwargs)
1700
- return if args.size > min || option('i', 'interactive', **kwargs, equals: '0')
1629
+ def command_args(args, force: false, **kwargs)
1630
+ return unless args.size == 1 && !option('i', 'interactive', **kwargs, equals: '0')
1701
1631
 
1702
1632
  readline('Enter arguments', force: force)
1703
1633
  end
@@ -1706,7 +1636,7 @@ module Squared
1706
1636
  if (ret = instance_eval(&blk)).nil?
1707
1637
  val
1708
1638
  else
1709
- Array(ret)
1639
+ ret.is_a?(Array) ? ret : [ret]
1710
1640
  end
1711
1641
  end
1712
1642
 
@@ -1742,17 +1672,6 @@ module Squared
1742
1672
  files.map { |val| val == '.' ? '.' : shell_quote(path + val) }
1743
1673
  end
1744
1674
 
1745
- def matchmap(list, prefix = nil)
1746
- list.map do |val|
1747
- if val.is_a?(Regexp)
1748
- val
1749
- else
1750
- val = ".*#{val}" if prefix && !val.sub!(/\A(\^|\\A)/, '')
1751
- Regexp.new("#{prefix}#{val == '*' ? '.+' : val}")
1752
- end
1753
- end
1754
- end
1755
-
1756
1675
  def semver(val)
1757
1676
  return val if val[3]
1758
1677
 
@@ -1766,56 +1685,23 @@ module Squared
1766
1685
  end
1767
1686
 
1768
1687
  def semscan(val, fill: true)
1769
- ret = val.scan(SEM_VER).first
1770
- fill ? semver(ret) : ret
1771
- end
1772
-
1773
- def semcmp(val, other)
1774
- return 0 if val == other
1775
-
1776
- a, b = [val, other].map! { |ver| ver.scan(SEM_VER) }
1777
- return -1 if b.empty?
1778
- return 1 if a.empty?
1779
-
1780
- a, b = [a.first, b.first].map! do |c|
1781
- begin
1782
- d = Integer(c[5]).to_s
1783
- rescue StandardError
1784
- d = c[5] ? '-1' : '0'
1785
- end
1786
- [c[0], c[2], c[4] || '0', d]
1787
- end
1788
- a.each_with_index do |c, index|
1789
- next if c == (d = b[index])
1790
-
1791
- return c.to_i < d.to_i ? 1 : -1
1792
- end
1793
- 0
1794
- end
1795
-
1796
- def semgte?(val, other)
1797
- semcmp(val, other) != 1
1688
+ val.scan(SEM_VER).first.yield_self { |data| fill ? semver(data) : data }
1798
1689
  end
1799
1690
 
1800
1691
  def indexitem(val)
1801
- [$1.to_i, $2 && $2[1..-1]] if val =~ /\A[=^#{indexchar}](\d+)(:.+)?\z/
1692
+ [$1.to_i, $2 && $2[1..-1]] if val =~ /\A\^(\d+)(:.+)?\z/
1802
1693
  end
1803
1694
 
1804
1695
  def indexerror(val, list = nil)
1805
1696
  raise_error("requested index #{val}", hint: list && "of #{list.size}")
1806
1697
  end
1807
1698
 
1808
- def indexchar
1809
- workspace.windows? ? '=' : '^'
1810
- end
1811
-
1812
1699
  def printsucc
1813
1700
  @@print_order += 1
1814
1701
  end
1815
1702
 
1816
1703
  def color(val)
1817
- ret = theme[val]
1818
- ret && !ret.empty? ? ret : [val]
1704
+ theme[val].yield_self { |styles| styles && !styles.empty? ? styles : [val] }
1819
1705
  end
1820
1706
 
1821
1707
  def colormap(val)
@@ -1838,9 +1724,9 @@ module Squared
1838
1724
  end
1839
1725
 
1840
1726
  def on(event, from, *args, **kwargs)
1841
- return unless from && @events.key?(event)
1727
+ return unless from && (data = @events[event])
1842
1728
 
1843
- Array(@events[event][from]).each do |obj|
1729
+ data[from]&.each do |obj|
1844
1730
  target, opts = if obj.is_a?(Array) && obj[1].is_a?(Hash)
1845
1731
  [obj[0], kwargs.empty? ? obj[1] : obj[1].merge(kwargs)]
1846
1732
  else
@@ -1857,49 +1743,27 @@ module Squared
1857
1743
  end
1858
1744
  end
1859
1745
 
1860
- def on_error(err, from, exception: self.exception, pass: false, dryrun: false)
1861
- log&.error err
1862
- unless dryrun
1863
- ret = on :error, from, err
1864
- raise err if exception && ret != true
1865
- end
1866
- print_error(err, pass: pass) unless ret
1867
- end
1868
-
1869
- def pwd_set(done = nil, pass: false, from: nil, dryrun: false)
1870
- pwd = Pathname.pwd
1871
- if block_given?
1872
- begin
1873
- if (path == pwd || pass == true) && (workspace.mri? || !workspace.windows?)
1874
- ret = yield
1875
- else
1876
- Dir.chdir path
1877
- ret = yield
1878
- Dir.chdir pwd
1879
- end
1880
- rescue StandardError => e
1881
- on_error(e, from, dryrun: dryrun)
1882
- else
1883
- ret
1884
- end
1885
- elsif @pwd == pwd
1886
- @pwd = nil
1887
- pwd unless done
1888
- elsif @pwd
1889
- return unless path == pwd
1890
-
1891
- Dir.chdir(@pwd)
1892
- @pwd = nil
1893
- elsif !done && path != pwd
1894
- @pwd = pwd
1746
+ def pwd_set(pass: false, from: nil)
1747
+ pwd = Dir.pwd
1748
+ if path.to_s == pwd || pass == true || (pass.is_a?(String) && semscan(pass).join <= RUBY_VERSION)
1749
+ ret = yield
1750
+ else
1895
1751
  Dir.chdir(path)
1896
- @pwd
1752
+ ret = yield
1753
+ Dir.chdir(pwd)
1897
1754
  end
1755
+ rescue StandardError => e
1756
+ puts e
1757
+ log&.error e
1758
+ ret = on(:error, from, e)
1759
+ raise if exception && ret != true
1760
+ else
1761
+ ret
1898
1762
  end
1899
1763
 
1900
1764
  def run_set(cmd, val = nil, opts: nil, **)
1901
- noopt = @output[1] == false && !@output[0].nil?
1902
- noenv = @output[2] == false
1765
+ diso = @output[1] == false && !@output[0].nil?
1766
+ dise = @output[2] == false
1903
1767
  parse = lambda do |data|
1904
1768
  ret = []
1905
1769
  if data[:command]
@@ -1919,8 +1783,8 @@ module Squared
1919
1783
  case cmd
1920
1784
  when Array
1921
1785
  @output = if cmd.all? { |data| data.is_a?(Hash) }
1922
- noopt = false
1923
- noenv = false
1786
+ diso = false
1787
+ dise = false
1924
1788
  cmd.map { |data| parse.call(data) }
1925
1789
  else
1926
1790
  cmd.dup
@@ -1931,14 +1795,14 @@ module Squared
1931
1795
  else
1932
1796
  @output[0] = cmd
1933
1797
  end
1934
- unless noopt
1798
+ unless diso
1935
1799
  if opts == false
1936
1800
  @output[1] = false
1937
1801
  elsif opts && opts != true
1938
1802
  @output[1] = opts
1939
1803
  end
1940
1804
  end
1941
- return if noenv
1805
+ return if dise
1942
1806
 
1943
1807
  if val.is_a?(Hash)
1944
1808
  @output[2] = val
@@ -1967,18 +1831,33 @@ module Squared
1967
1831
  @parent = val if val.is_a?(Project::Base)
1968
1832
  end
1969
1833
 
1834
+ def exception_set(val)
1835
+ @exception = env_bool(val, workspace.exception, strict: true)
1836
+ end
1837
+
1838
+ def pipe_set(val)
1839
+ @pipe = env_pipe(val, workspace.pipe, strict: true)
1840
+ end
1841
+
1842
+ def verbose_set(val)
1843
+ @verbose = case val
1844
+ when NilClass
1845
+ workspace.verbose
1846
+ when String
1847
+ env_bool(val, workspace.verbose, strict: true, index: true)
1848
+ else
1849
+ val
1850
+ end
1851
+ end
1852
+
1970
1853
  def graph_set(val)
1971
1854
  @graph = if val
1972
- Array(val).map { |s| workspace.prefix ? workspace.task_name(s).to_sym : s.to_sym }.freeze
1855
+ as_a(val).map { |s| workspace.prefix ? workspace.task_name(s).to_sym : s.to_sym }.freeze
1973
1856
  end
1974
1857
  end
1975
1858
 
1976
1859
  def pass_set(val)
1977
- @pass = Array(val).freeze
1978
- end
1979
-
1980
- def only_set(val)
1981
- @only = val && as_a(val, :to_s).freeze
1860
+ @pass = (val ? as_a(val, :to_s) : []).freeze
1982
1861
  end
1983
1862
 
1984
1863
  def exclude_set(val)
@@ -2026,7 +1905,7 @@ module Squared
2026
1905
  unless @pass.include?(key.to_s) || ws.task_defined?(name, action) || ws.task_exclude?(action, self)
2027
1906
  ws.task_desc(@desc, action)
2028
1907
  task action do
2029
- __send__(key)
1908
+ __send__ key
2030
1909
  end
2031
1910
  end
2032
1911
  next if (items = @children.select { |item| item.task_include?(key) }).empty?
@@ -2037,17 +1916,10 @@ module Squared
2037
1916
  end
2038
1917
  end
2039
1918
 
2040
- def task_pass?(key)
2041
- @only ? !@only.include?(key) : @pass.include?(key)
2042
- end
2043
-
2044
- def matchany?(val, list, empty: true)
2045
- list.empty? ? empty : list.any? { |pat| val.match?(pat) }
2046
- end
2047
-
2048
1919
  def projectpath?(val)
2049
- val = Pathname.new(val).cleanpath
2050
- val.absolute? ? val.to_s.start_with?(File.join(path, '')) : !val.to_s.start_with?(File.join('..', ''))
1920
+ Pathname.new(val).cleanpath.yield_self do |file|
1921
+ file.absolute? ? file.to_s.start_with?(File.join(path, '')) : !file.to_s.start_with?(File.join('..', ''))
1922
+ end
2051
1923
  end
2052
1924
 
2053
1925
  def checkdir?(val)
@@ -2099,22 +1971,17 @@ module Squared
2099
1971
  return false if workspace.series.chain?(val = task_join(name, action))
2100
1972
  return true if task_invoked?(val) && (!task_invoked?(ac) || !workspace.task_defined?(ac, 'sync'))
2101
1973
 
2102
- val = workspace.series.name_get(action)
2103
- val != action && invoked_sync?(val)
1974
+ workspace.series.name_get(action).yield_self { |name| name != action && invoked_sync?(name) }
2104
1975
  end
2105
1976
 
2106
- def success?(ret, display = true)
2107
- ret == true && display && stdout? && banner?
1977
+ def success?(ret)
1978
+ ret == true && stdout? && banner?
2108
1979
  end
2109
1980
 
2110
1981
  def banner?
2111
1982
  ARG[:BANNER] && !env('BANNER', equals: '0')
2112
1983
  end
2113
1984
 
2114
- def pwd?
2115
- path == Pathname.pwd
2116
- end
2117
-
2118
1985
  def stdin?
2119
1986
  pipe == 0
2120
1987
  end
@@ -2146,16 +2013,8 @@ module Squared
2146
2013
  BLK_SET
2147
2014
  end
2148
2015
 
2149
- def hashobj
2150
- Workspace::Support.hashobj
2151
- end
2152
-
2153
- def hashlist
2154
- Workspace::Support.hashlist
2155
- end
2156
-
2157
2016
  def borderstyle
2158
- ((data = workspace.banner_get(*@ref, group: group)) && data[:border]) || theme[:border]
2017
+ workspace.banner_get(*@ref, group: group)&.border || theme[:border]
2159
2018
  end
2160
2019
 
2161
2020
  def headerstyle
@@ -2168,7 +2027,7 @@ module Squared
2168
2027
  end
2169
2028
 
2170
2029
  Application.implement(Base, base: true)
2171
- Application.attr_banner = Common::SymSet.new(%i[name project path ref group parent])
2030
+ Application.attr_banner = Set.new(%i[name project path ref group parent])
2172
2031
  end
2173
2032
  end
2174
2033
  end